【问题标题】:Update strings in a text file at a specific location在特定位置更新文本文件中的字符串
【发布时间】:2012-05-29 12:02:15
【问题描述】:

我想找到一个更好的解决方案来实现以下三个步骤:

  1. 读取给定行的字符串
  2. 更新字符串
  3. 写回更新的字符串

下面是我的代码,但我想知道有没有更好(简单)的解决方案?

new='99999'

f=open('C:/Users/th/Dropbox/com/MS1Ctt-P-temp.INP','r+')
lines=f.readlines()
#the row number we want to update is given, so just load the content
x = lines[95]
print(x)
f.close()


#replace
f1=open('C:/Users/th/Dropbox/com/MS1Ctt-P-temp.INP')
con = f1.read()
print con
con1 = con.replace(x[2:8],new) #only certain columns in this row needs to be updated
print con1
f1.close()


#write
f2 = open('C:/Users/th/Dropbox/com/MS1Ctt-P-temp.INP', 'w')
f2.write(con1)
f2.close()

谢谢! 更新:从 jtmoulia 那里得到一个想法,这次它变得更容易了

def replace_line(file_name, line_num, col_s, col_e, text):
    lines = open(file_name, 'r').readlines()
    temp=lines[line_num]
    temp = temp.replace(temp[col_s:col_e],text)
    lines[line_num]=temp
    out = open(file_name, 'w')
    out.writelines(lines)
    out.close()

【问题讨论】:

    标签: python string text io


    【解决方案1】:

    文本数据的问题是,即使是在表格中,字节偏移量也是不可预测的。例如,当用字符串表示数字时,每个数字有一个字节,而在使用二进制(例如二进制补码)时,无论是小整数还是大整数,您总是需要四个或八个字节。

    不过,如果您的文本格式足够严格,您可以通过替换字节而不改变文件大小来解决问题,您可以尝试使用standard mmap module。有了它,您将能够将文件视为 可变 字节字符串并就地修改它的部分内容,并让内核为您保存文件。

    否则,任何其他答案都更适合该问题。

    【讨论】:

    • 好点。但是我的一些替换会改变字符串的长度,比如将 0111 更改为 01110。这是否意味着 mmap 对我不起作用,对吧?
    • 正确,它不起作用。使用mmap 调整文件大小比读取/写入要复杂得多:您需要提前知道新文件的大小,在映射文件之前将文件截断到该大小,然后手动移动内容,具体取决于您的位置进行修改。
    【解决方案2】:

    好吧,首先,您不需要每次都重新打开并从文件中读取。 r+ 模式允许您读取和写入给定文件。

    也许是这样的

    with open('C:/Users/th/Dropbox/com/MS1Ctt-P-temp.INP', 'r+') as f:
        lines = f.readlines()
        #... Perform whatever replacement you'd like on lines
        f.seek(0)
        f.writelines(lines)
    

    另外,Editing specific line in text file in python

    【讨论】:

      【解决方案3】:

      当我不得不做类似的事情时(对于 Webmin 定制),我完全在 PERL 中完成,因为这是 Webmin 框架使用的,而且我发现它很容易。我假设(但不确定)在 Python 中有等价的东西。首先将整个文件一次全部读入内存(PERL 的方法可能称为“slurp”)。 (这种将整个文件保存在内存中而不仅仅是一行的想法过去没有什么意义{甚至是不可能的}。但是现在 RAM 太大了,这是唯一的出路。)然后使用 split 运算符将文件分成几行,并将每一行放在一个巨型数组的不同元素中。然后,您可以使用所需的行号作为数组的索引(记住数组索引通常以 0 开头)。最后,使用“正则表达式”处理来改变行的文本。然后更改另一行,另一行,另一行(或对同一行进行另一次更改)。完成后,使用join 将数组中的所有行重新组合成一个巨大的字符串。然后将整个修改后的文件写出来。

      虽然我手头没有完整的代码,但这里有一些 PERL 代码的大致片段,因此您可以明白我的意思:

      our @filelines = ();
      our $lineno = 43;
      our $oldstring = 'foobar';
      our $newstring = 'fee fie fo fum';
      $filelines[$lineno-1] =~ s/$oldstring/$newstring/ig; 
      # "ig" modifiers for case-insensitivity and possible multiple occurences in the line
      # use different modifiers at the end of the s/// construct as needed
      

      【讨论】:

      • 读入整个文件是唯一的方法,但仍然没有意义,我们可以处理的文件大小增加了,因为可用的内存量增加了,反之亦然。对于千兆字节范围内的文件,slurp 会变得窒息。
      • 你可能是对的。以我的经验,任何文本文件都可以打印出来并带到比萨店查看。此类文件的范围通常从几 K 到几百 K。我从来没有像千兆字节文本文件这样的远程操作经验。 (即便如此,我怀疑在具有 4GB RAM 的系统上,使用数组会使处理 1GB 文本文件变得非常容易,这可能是值得的。旧习惯很难改掉。我们一直在一次一行地读取文件现在已经 40 多年了,这样做的充分理由越来越少:-)
      • 感谢您的评论。我认为linecache.getline 可以逐行阅读文本。但我只是不确定如何将替换的内容保存到正确的位置。
      • 抱歉,我知道 Perl 的语言结构,但不知道 Python 的语言结构。对我有用的东西可能对你没那么好;忽略我的回答可能会更好。我说的是把整个文件放在一个巨大的数组中,这样你就可以在不重新阅读的情况下触摸任何你想要的行——“逐行阅读文本”的想法表明你仍在考虑一些完全不同的东西。在 Perl 中, s/// 结构修改了原来的位置; “将修改后的文本替换到适当的位置”的想法甚至从未出现过。
      【解决方案4】:
      FILENAME = 'C:/Users/th/Dropbox/com/MS1Ctt-P-temp.INP'
      lines = list(open(FILENAME))
      lines[95][2:8] = '99999'
      open(FILENAME, 'w').write(''.join(lines))
      

      【讨论】:

      • 字符串不可变,即 `lines[95][2:8] = '99999' 不起作用。
      猜你喜欢
      • 2020-07-25
      • 2019-11-17
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      • 2016-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多