I'm going to create script which will take the key and value from the dictionary and use it for replacement in set of files. I need replace "foo" to "foo1" if "target_value" found in the file. There are many different foo's. So, I guess dictionary will be suitable for that.
I started from the simple things:
with fileinput.FileInput(filelist, inplace=True) as file:
for line in file:
if line.find('target_value'):
print(line.replace("foo", "foo1"), end='')
For some reason this script just ignore line.find and replace everything with last line of code. Could you help?
CodePudding user response:
Python's find command returns -1 if the value is not found, so you need something like:
with fileinput.FileInput(filelist, inplace=True) as file:
for line in file:
if line.find('target_value') > -1:
line = line.replace("foo", "foo1")
print(line, end='')
CodePudding user response:
The trouble with str.find
is that it returns the index at which "target_value"
occurs in line
, so any integer from 0 to len(line)-len(target_value)-1
. That is, unless, "target_value"
doesn't exist in line
; then str.find
returns -1
but the value of bool(-1)
is True
. In fact, the only time line.find('target_value')
is False
is when "target_value"
is the first part of line
.
There are a couple options:
with fileinput.FileInput(filelist, inplace=True) as file:
for line in file:
if line.find('target_value') != -1:
print(line.replace("foo", "foo1"), end='')
Or:
with fileinput.FileInput(filelist, inplace=True) as file:
for line in file:
if 'target_value' in line:
print(line.replace("foo", "foo1"), end='')
The second option is more readable and tends to perform better when line
is long and "target_value"
doesn't occur in the beginning of line
.
>>> timeit('"target_value" in s', setup='s = "".join("foobar baz" for _ in range(100)) "target_value" "".join("foobar baz" for _ in range(100))') 0.20444475099975534 >>> timeit('s.find("target_value") != -1', setup='s = "".join("foobar baz" for _ in range(100)) "target_value" "".join("foobar baz" for _ in range(100))') 0.30517548999978317
CodePudding user response:
Instead of .find()
, you can use if 'target_value' in line:
which is more expressive and does not involve return value conventions.
If you have multiple target keywords (and multiple replacements per target), you could build your dictionary in like this
replacements = { 'target_value1': [('foo','foo1'), ('bar','bar1')],
'target_value2': [('foo','foo2'), ('bar','bar2')],
'target_value3': [('foobar','foosy'),('barfoo','barry')]}
Then find which target value(s) are present and perform the corresponding replacements:
with open(fileName,'r') as f:
content = f.read()
for target,maps in replacements.items(): # go through target keywords
if target not in content: continue # check target (whole file)
for fromString,toString in maps: # perform replacements for target
content = content.replace(fromString,toString)
# you probably want to save the new content at this point
with open(fileName,'w') as f:
f.write(content)
Note that, in this example, I assumed that the target keyword flags the whole file (not each line). If the target keyword is specific to each line, you will need to break down the content into lines and place the logic inside a loop on lines to perform the replacements on a line by line basis
You don't actually need the replacement data to be a dictionary:
replacements = [ ['target_value1',('foo','foo1'), ('bar','bar1')],
['target_value2',('foo','foo2'), ('bar','bar2')],
['target_value3',('foobar','foosy'),('barfoo','barry')]]
with open(fileName,'r') as f:
content = f.read()
for target,*maps in replacements: # go through target keywords
if target not in content: continue
for fromString,toString in maps: # perform replacements for target
content = content.replace(fromString,toString)