简体   繁体   English

每 20 分钟编辑 python 文件中的特定单词

[英]Editing a SPECIFIC word in a file in python, every 20 mins

I want to change the value of omega in the file below at a specific interval, say every 30 minutes.我想以特定的时间间隔更改下面文件中 omega 的值,比如每 30 分钟一次。 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.我想缓慢地将 RPM 值(行中的最后一个条目)从 0 增加到 10。 Essentially, the value "5" in the file below needs to change from 0-10 in increments of 1 every 30 minutes.本质上,下面文件中的值“5”需要以每 30 分钟 1 的增量从 0-10 变化。

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.我尝试了以下代码(我不知道如何执行每 30 分钟部分),但file.writelines(data)方法写入的数据似乎没有包含我对值所做的更改。

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.这不起作用 - 更新文件中的 5 未更改为 10。 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.您根本没有修改data - 您正在提取lineword并修改它们。 In the end, you write back the original data to the file.最后,您将原始data写回文件。

I would not use Python for this, but rather a shell script (provided you are on a Unix-like OS):我不会为此使用 Python ,而是使用 shell 脚本(前提是您使用的是类 Unix 操作系统):

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:您可以通过导入的fileinput模块和正则表达式的re模块来识别行及其组件:

>>> 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) !大括号用于捕获模式,请查看re 模块以了解更多信息(非常有用的 Python 模块,做得很好并记录在案)!

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).我们有了我们的模式,现在浏览我们的文件: print用于直接写入文件(不再打印到屏幕),标准 function 在for循环结束时恢复正常(文件关闭)。

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 ) !不要忘记删除换行符以避免 output 文件中出现不需要的换行符(是的,这有点烦人:循环给出的line变量包含换行符\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 .您现在可以浏览旧文件,值5已替换为145 I personally don't agree with Sven, Python is for me the perfect language to deal with this kind of situation.我个人不同意 Sven 的观点,Python 对我来说是处理这种情况的完美语言。

The canonical way of doing what you want is indeed to use the regular expression module ( re ).做你想做的事的规范方法确实是使用正则表达式模块( re )。 It can perform the replacement in the "omega" line directly:它可以直接在“omega”行中执行替换:

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+':使用 Python,您可以使用正则表达式并在模式为“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: m是记录匹配结果的MatchObject,这些结果中,有:

  • the position in the file's content where starts the 1 or 2 digit(s) sequence that is catched by the first group in the match, the one defined by (\d\d?) .文件内容中的 position 开始由匹配中的第一组捕获的 1 或 2 位序列,该组由(\d\d?)定义。 This start is obtained via method start() of m called with 1 as argument这个开始是通过以 1 作为参数调用的m的方法start()获得的
  • the text catched by second group in the match, defined by (;.+) , obtained by method group() of m called with 2 as argument匹配中第二组捕获的文本,由(;.+)定义,由m的方法group()获得,以 2 作为参数调用

re.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. re.MULTILINE使正则表达式模式中的符号'^'与每个行首匹配,即恰好在每个'\n'之后和字符串的开头。 Without re.MULTILINE , '^' means only the matching with the beginning of the string如果没有re.MULTILINE'^'仅表示与字符串开头的匹配

re.DOTALL makes the dot in the pattern to match with any character, comprised the newlines. re.DOTALL使模式中的点与任何字符匹配,包括换行符。 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.如果没有re.DOTALL ,模式中的符号点将在行尾停止匹配。

After the execution of f.read() , the file's pointer is situated at the end of the file on the hard drive.执行f.read()后,文件的指针位于硬盘驱动器上文件的末尾。 seek() allows to move it. seek()允许移动它。 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)在这种情况下, seek(x,0)将指针移动到 position,它位于文件开头的x 个字符处(0 表示“从头开始”,请参阅 seek() 以了解其他类型的移动)

After the execution of f.seek(x,0) , the pointer is just before the integer you want to change.执行f.seek(x,0)后,指针就在您要更改的 integer 之前。 Writing str(i) erases and writes on the ancient number.写入str(i)擦除并写入古代数字。

f.truncate() is to make the file ending at the current position. f.truncate()是使文件以当前 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请注意,如果在文件中为可以写入两个字符的数字保留两个位置,则可以简化此代码:'0'、'1'、'2'、'3'等

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.模式中符号序列[ \d.eE+-]的括号'['']'定义了一组字符。 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)我选择用模式的\[[ \d.eE+-]+\]部分来捕捉'[0 0 -1 0 0 0 0]'以防数字可能是任何其他类型的数字,以任何形式表示表示形式(包括指数符号)

' +' in the pattern means 'any number of blanks'模式中的' +'表示“任意数量的空格”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM