2

I have a dict with a few {key, value} pairs. I also have a file with some content.

The file is something like this:

some random text

...

...

text-which-matches-a-key

some important lines

...

...

some other important text until end of file

What I want is, to search/iterate through the file until a line matches a key of the dict, the append the corresponding value before/after some important lines

What I've tried to do is this:

with open('file', 'a+') as f:
    for key in a:
        if f.readlines() == key:
            f.writelines(a[key])
f.close()

where a is a dict, with many key,value pairs.

I'd be happy if the results are something like:

some random text

...

...

text-which-matches-a-key

some important lines

value corresponding to the key

...

...

some other important text until end of file

or:

some random text

...

...

text-which-matches-a-key

value corresponding to the key

some important lines

...

...

some other important text until end of file

Any help is appreciated.

P.S: Using Python 2.7, on PyCharm, on Windows 10.

  • As my answer to your previous question was the only one which returned your requested data as a dict, I assume you liked it and use it now for your task. In such cases I'd appreciate at least some "thanks" or an upvote instead of – SpghttCd Dec 21 '18 at 13:23

6 Answers6

2

The script below can not insert multiple dictionary values. The value of the last dictionary key that appears before 'some important lines' in the file is inserted.

dictionary = {'text-which-matches-a-key': 'value corresponding to the key'}

# Open file and fill a list in which each element is a line.
f = open('file', 'r')
lines = f.readlines()
f.close()

# Empty the file.
f = open('file', 'w')
f.close()

# Insert dictionary value at the right place.
for index, line in enumerate(lines):
    '''Remove the newline character '\n'
    to the right of the strings in the file.
    The lines don't match dictionary keys if
    the dictionary keys don't have newlines
    appended.'''
    line = line.rstrip()
    # Check if any line is a key in the dictionary.
    if line in dictionary.keys():
        key_occurs_in_text = True
        key_occurring_in_text = line
    ''' 'some important lines' is reached and a key
    of the dictionary has appeared as a line in the
    file. Save the list index which corresponds to
    the line after or before 'some important lines' in
    the variable insert_index. '''
    if 'some important lines' == line and key_occurs_in_text:
        insert_index = index + 1
        # insert_index = index - 1

'''A line in the file
is a key in the dictionary.
Insert the value of the key at the index we saved
in insert_index.
Prepend and append newline characters to match
the file format.'''
if key_occurs_in_text:
    lines.insert(insert_index, '\n'+dictionary[key_occurring_in_text]+'\n')

# Write the changed file content to the empty file.
f = open('file', 'w')
for line in lines:
    f.write(line)
f.close
Osvald Laurits
  • 1,228
  • 2
  • 17
  • 32
  • I used your script, with a slight change, while iterating over the dict that i have. It worked with one slight difference. The text I need added is added at the start of the file. I tried to debug, with no result. Can you check that? The code I'd modified is adding `for i in b: dictionary = {i: b[i]}` at the start of the script – Yogesh Sudheer Modak Dec 24 '18 at 06:52
  • Also, getting this:`NameError: name 'key_occurring_in_text' is not defined` – Yogesh Sudheer Modak Dec 24 '18 at 09:13
  • Can you upload the script with your modifications and the text file you want to modify to github? Then I can examine why the text is added at the start of the file. I tested the script with the text file you provide in your question. You can clone it from [github](https://github.com/michaelhochleitner/insert_dict_value) and test it. Using the file in the repository as input, the text is inserted at the right place. – Osvald Laurits Dec 25 '18 at 12:51
  • Thanks for the offer, but I tinkered around with dicts and files and got the output I required. – Yogesh Sudheer Modak Dec 26 '18 at 05:20
2

Your second version, i.e. inserting directly after the key line is quite simple.
If you don't mind loading the whole file into memory it's just

with open('file', 'r') as f:
    txt = f.readlines()

with open('file', 'w') as f:
    for line in txt:
        f.write(line)
        if line.strip() in block:
            f.write(block[line.strip()])

with block being your dictionary.

However, if you do not want to load the whole file at once, you have to write to a different file than your source file, because inserting into files (in opposite to overwriting portions of a file) is not possible:

with open('source_file', 'r') as fs, open(target_file,'w') as ft:
    for line in fs:
        ft.write(line)
        if line.strip() in block:
            ft.write(block[line.strip()])

Of course it would be possible to e.g. rename the source file first and then write everything to the original filename.


Regarding the first version, i.e. leaving several important lines after the key and insert the block after these lines, well, that would require a proper definition of how to decide which or how many lines are important.

However, if it's just about a fix number of lines N after the key line:

with open(file, 'r') as f:
    txt = f.readlines()

with open(file, 'w') as f:
    N = 3
    i = -1
    for line in txt:
        f.write(line)
        if i == N:
            f.write(block[key])
            i = -1
        if line.strip()in block:
            key = line.strip()
            i = 0
        if i >= 0:
            i += 1

... or without loading all at once into memory:

with open('source_file', 'r') as fs, open(target_file,'w') as ft:
    N = 3
    i = -1
    for line in fs:
        ft.write(line)
        if i == N:
            ft.write(block[key])
            i = -1
        if line.strip()in block:
            key = line.strip()
            i = 0
        if i >= 0:
            i += 1      
SpghttCd
  • 10,510
  • 2
  • 20
  • 25
1
  1. There's a difference between readline() and readlines() (the former reads 1 line, the latter reads all lines and returns a list of strings).
    See: https://docs.python.org/2.7/tutorial/inputoutput.html

  2. It'd be easier to just read the entire file, apply your changes to it, and write it back to a file once you're done, rather than trying to edit the file inplace.
    See: Editing specific line in text file in python

  3. You don't have to manually close the file when you're useing the with-statement. The file will automatically close when you leave the with-block.

orangeInk
  • 1,360
  • 8
  • 16
0

a+ means read and append, what you want is r+ which writes a new line at the cursor location.

Employee
  • 1
  • 2
0

Try this:

import fileinput

file = fileinput.FileInput(your_text_file, inplace=True)
for line in file:
    for key, value in yourdictionary.iteritems():
        line.replace(key, key + '\n' + value)
file.close()
Dude
  • 249
  • 2
  • 8
0

After trying a few things mentioned here, and tinkering around with files and dictionaries, I finally came up with this snippet that works for me:

with open("input") as f:
    data_file = f.read()
f.close()
data = data_file.splitlines()
f = open('output', 'w')
for line in data:
    if line.strip() in b.keys():
        line = line.strip() + '\n' + b[line.strip()].rstrip() + '\n'
        f.writelines(line)
    else:
        f.writelines(line + '\n')
f.close()

where data is the content of the original file, and b is my dictionary of keys and values.

I don't know if answering my own question is allowed or not, but it got me the right output, hence posting it anyway.