I want to change the value of omega in the file below at a specific interval, say every 30 minutes. This file is used by another program at runtime. I would like to ramp the RPM value (the last entry on the line) from 0-10 slowly. Essentially, the value "5" in the file below needs to change from 0-10 in increments of 1 every 30 minutes.
rotor
{
// Fixed patches (by default they 'move' with the MRF zone)
nonRotatingPatches (); //if something blows up ..fill the non rotating patches between "(baffles, pressureOutlet etc)"
origin origin [0 1 0 0 0 0 0] (0 0 0);
axis axis [0 0 0 0 0 0 0] (0 0 1);
omega omega [0 0 -1 0 0 0 0] 5;
}
I have tried the following code (I don't know how to do the every 30 minutes part), but the data written by the file.writelines(data)
method doesn't seem to incorporate the change I make to the value.
import os
import sys
import fileinput
with open('MRFzones', 'r') as file:
data = file.readlines()
# The line omega is line 27 in the file.
line = data[26]
word = line.split()
# >>> data[26].split()
# ['omega', 'omega', '[0', '0', '-1', '0', '0', '0', '0]', '5;']
# The part i want to change is the 10th word.
word[9] = '10;'
# Write everything back.
with open('MRFzones', 'w') as file:
file.writelines(data)
This is not working - the 5 is not being changed into 10 in the updated file. Can someone help me implement this? I might not even have the right idea, so we could start the code from scratch if necessary.
Thanks, Suresh
You are not modifying data
at all -- you are extracting line
and word
and modify those. In the end, you write back the original data
to the file.
I would not use Python for this, but rather a shell script (provided you are on a Unix-like OS):
for i in 0 1 2 3 4 5 6 7 8 9 10; do
sleep 30
sed -i "26s/[0-9]+;/$i/" MRFzones
od
You can identify your lines and its components via the fileinput
module you imported, and the re
module for regular expressions:
>>> import re
>>> pattern = r'(\s*omega\s+omega\s+\[-?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+ -?\d+\]) (-?\d+);'
Enclosing braces are used to capture patterns, have a look at the re module to know more (very useful Python module, very well done and documented) !
We have our pattern, now browse our file inplace: print
is used to write in the file directly (no longer prints to screen), standard function comes back to normal when the for
loop is over (file closed).
Don't forget to remove newlines to avoid having unrequired newlines in your output file (yes this is a bit annoying: the line
variable given by the loop contains a newline \n
) !
>>> from fileinput import FileInput
>>> path = 'D:\\Temp\\Toto.txt'
>>> for line in FileInput(path, inplace=1):
line = line.replace('\n', '')
match = re.match(pattern, line)
if match:
line = '{0} {1};'.format(match.groups()[0], '145')
print line
else:
print line
You can now browse your old file, the value 5
was replaced by 145
. I personally don't agree with Sven, Python is for me the perfect language to deal with this kind of situation.
The canonical way of doing what you want is indeed to use the regular expression module ( re ). It can perform the replacement in the "omega" line directly:
import re
for count in range(10):
# Reading:
with open('MRFzones') as input_file: # Automatically closes the file after reading
contents = input_file.read() # Whole file
# Writing:
with open('MRFzones', 'w') as out_file:
# The 'omega.*(\d+)' searches for a line with "omega" followed at some point by digits and ";". sub() performs
# a substitution of the part matched inside the parentheses:
out_file.write(re.sub('omega +(\d+);', str(count), contents, count=1)) # count=1 only modifies the first omega line
With Python, you could use a regex and processing in a file with mode 'rb+':
import re
from time import sleep
regx = re.compile('^ +omega +omega +\[[ \d.eE+-]+\] +(\d\d?)(;.+)',re.MULTILINE|re.DOTALL)
for i in xrange(1,11):
sleep(20*60)
with open('MRFzones', 'rb+') as f:
m = regx.search(f.read())
x = m.start(1)
f.seek(x,0)
f.writelines((str(i),m.group(2)))
f.tuncate()
I suppose that the initial file is containing
' omega omega [0 0 -1 0 0 0 0] 0;'
m is the MatchObject that records the results of the matching Among these results, there are:
(\d\d?)
. This start is obtained via method start() of m called with 1 as argument(;.+)
, obtained by method group() of m called with 2 as argumentre.MULTILINE makes the symbol '^' in the pattern of the regex to match with each start of line, that is precisely after each '\n'
and at the beginning of the string. Without re.MULTILINE , '^' means only the matching with the beginning of the string
re.DOTALL makes the dot in the pattern to match with any character, comprised the newlines. So ';.+'
means: the character ';' and all and every characters that follow ';'until the very end of the string. Without re.DOTALL , the symbolic dot in the pattern would stop to match at the end of the line.
After the execution of f.read()
, the file's pointer is situated at the end of the file on the hard drive. seek() allows to move it. In this case, seek(x,0)
moves the pointer to a position that is situated at x characters from the start of the file (the 0 means 'from the start', see seek() to learn the other types of moves)
After the execution of f.seek(x,0)
, the pointer is just before the integer you want to change. Writing str(i) erases and writes on the ancient number.
f.truncate()
is to make the file ending at the current position. In the case of my code, it's not absolutely necesssary, since the string that is replaced is always replaced by a string of same or longer length.
.
Note that this code can be simplified if there are two positions reserved for the number in the file where can be written two characters: ' 0', ' 1', ' 2', ' 3', etc
In this case the code can be:
import re
from time import sleep
regx = re.compile('^ +omega +omega +\[[ \d.eE+-]+\] +(\d\d?)',re.MULTILINE)
for i in xrange(1,11):
sleep(20*60)
with open('MRFzones', 'rb+') as f:
m = regx.search(f.read())
x = m.start(1)
f.seek(x,0)
f.write('{:>2}'.format(i))
or
import re
from time import sleep
regx = re.compile('^ +omega +omega +\[[ \d.eE+-]+\] +(\d\d?)(;.+)',re.MULTILINE|re.DOTALL)
with open('Copie de oso.txt', 'rb+') as f:
m = regx.search(f.read())
x = m.start(1)
f.seek(x,0)
f.writelines((' 1',m.group(2)))
f.truncate()
for i in xrange(2,11):
sleep(20)
with open('Copie de oso.txt', 'rb+') as f:
f.seek(x,0)
f.write('{:>2}'.format(i))
.
PS
Brackets '[' and ']' of the symbolic sequence [ \d.eE+-]
in the pattern define a set of characters. I put between these two brackets all the characters that are likely to be used to write a number. It is important that '-' be at the end of the set, otherwise it would mean anaother thing that just the '-' character.
'\['
and '\]'
are the escaped brackets, to represent just the characters 'brackets', not the symbolic brackets that define a set
I choosed to catch '[0 0 -1 0 0 0 0]' with the part \[[ \d.eE+-]+\]
of the pattern in case that the numbers could be any other kind of number, expressed in any sort of representation (comprised exponential notation)
' +'
in the pattern means 'any number of blanks'
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.