9

I'm trying to open a text file and then read through it replacing certain strings with strings stored in a dictionary.

Based on answers to How do I edit a text file in Python? I could pull out the dictionary values before doing the replacing, but looping through the dictionary seems more efficient.

The code doesn't produce any errors, but also doesn't do any replacing.

import fileinput

text = "sample file.txt"
fields = {"pattern 1": "replacement text 1", "pattern 2": "replacement text 2"}

for line in fileinput.input(text, inplace=True):
    line = line.rstrip()
    for i in fields:
         for field in fields:
             field_value = fields[field]

             if field in line:
                  line = line.replace(field, field_value)


             print line
Community
  • 1
  • 1
David Manning
  • 93
  • 1
  • 2
  • 5

6 Answers6

5

I used items() to iterate over key and values of your fields dict.

I skip the blank lines with continue and clean the others with rstrip()

I replace every keys found in the line by the values in your fields dict, and I write every lines with print.

import fileinput

text = "sample file.txt"
fields = {"pattern 1": "replacement text 1", "pattern 2": "replacement text 2"}


for line in fileinput.input(text, inplace=True):
    line = line.rstrip()
    if not line:
        continue
    for f_key, f_value in fields.items():
        if f_key in line:
            line = line.replace(f_key, f_value)
    print line
Kruupös
  • 5,097
  • 3
  • 27
  • 43
  • Thanks, this works. I used a variation: `code` for line in fileinput.input(text, inplace=False): line = line.rstrip() if not line: continue for f_key, f_value in field_value_dict.items(): if f_key in line: line = line.replace(f_key, f_value) file.write(line + '\n') file.close() `code` – David Manning Mar 31 '17 at 15:02
2

Just figured out how to replace lots of different words in a txt file at one go, by iterating through a dictionary (whole word matches only). It would be really annoying if I want to replace "1" with "John", but ends up turning "12" into "John2." The following code is what works for me.

import re

match = {}  # create a dictionary of words-to-replace and words-to-replace-with

f = open("filename","r")
data = f.read() # string of all file content

def replace_all(text, dic):
    for i, j in dic.items():
        text = re.sub(r"\b%s\b"%i, j, text) 
        # r"\b%s\b"% enables replacing by whole word matches only
    return text

data = replace_all(data,match)
print(data) # you can copy and paste the result to whatever file you like
Chris Zhu
  • 29
  • 1
1

If you can find a regex pattern covering all your keys, you could use re.sub for a very efficient solution : you only need one pass instead of parsing your whole text for each search term.

In your title, you mention "replacing words". In that case, '\w+' would work just fine.

import re

fields = {"pattern 1": "replacement text 1", "pattern 2": "replacement text 2"}

words_to_replace = r'\bpattern \d+\b'

text = """Based on answers to How do I edit a text file in Python? pattern 1 I could pull out
the dictionary values before doing the replacing, but looping through the dictionary seems more efficient.
Test pattern 2
The code doesn't produce any errors, but also doesn't do any replacing. pattern 3"""

def replace_words_using_dict(matchobj):
    key = matchobj.group(0)
    return fields.get(key, key)

print(re.sub(words_to_replace, replace_words_using_dict, text))

It outputs :

Based on answers to How do I edit a text file in Python? replacement text 1 I could pull out
the dictionary values before doing the replacing, but looping through the dictionary seems more efficient.
Test replacement text 2
The code doesn't produce any errors, but also doesn't do any replacing. pattern 3

Also, be very careful when modifying a file in place. I'd advice you to write a second file with the replacements. Once you are 100% sure that it works perfectly, you could switch to inplace=True.

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • 1
    You could use the dict's keys to get the match regexp, e.g. words_to_replace = "|".join(fields.keys()) to replace all occurrences, or words_to_replace = r"\b({})\b".format("|".join(fields.keys())) to require the occurrences to be isolated words – Ethan Bradford May 20 '19 at 20:45
  • Yes, that would also work. If the regex union is too slow, it's possible to create a Regex trie: https://stackoverflow.com/a/42789508/6419007 – Eric Duminil May 21 '19 at 09:55
0
import fileinput

text = "sample file.txt"
fields = {"pattern 1": "replacement text 1", "pattern 2": "replacement text 2"}

for line in fileinput.input(text, inplace=True):
    line = line.rstrip()
    for field in fields:
        if field in line:
            line = line.replace(field, fields[field])

    print line
S.Doe
  • 49
  • 1
  • 10
0

If You are more familiar with Python, You can use tips from Official documentation:

7.1. string — Common string operations

And subclass, the Template class, in which you define somehow that every single world will be a new placeholder, and then with safe_substitute() You could get a nice and reliable solution.

Take_Care_
  • 1,957
  • 1
  • 22
  • 24
-1

This is how I would do it:

fields = {"pattern 1": "replacement text 1", "pattern 2": "replacement text 2"}

with open('yourfile.txt', 'w+') as f:
    s = f.read()
    for key in fields:
        s = s.replace(key, fields[key])
    f.write(s)
crux666
  • 87
  • 4
  • That's exactly the reason why modifying a file in place is a very bad idea. Your code wipes `'yourfile.txt'`. – Eric Duminil Mar 31 '17 at 12:05
  • Sorry, I typed this in a hurry, `s.replace()` needs to be assigned to `s` and I fixed the typo. Also, the code does wipe the file, but replaces it with the "updated" string, obviously if the file contains crucial information, operate on a copy before replacing the content. – crux666 Mar 31 '17 at 12:24
  • Your code still wipes the file, then reads it, then replaces it with nothing and then saves nothing back to the file. Could you please test your potentially dangerous code before posting it? – Eric Duminil Mar 31 '17 at 12:29