根据文本文件中的位置替换特定单词(Python)

时间:2016-04-27 16:21:51

标签: python python-3.x

我有一个元组列表,每个元组包含一个要替换的字,它的行和列号位置来自给定的文本文件。我想浏览文本文件并用字符替换该特定位置的特定字词(例如[('word1', 1, 1), ('word2', 1, 9), ... ])。

换句话说,给定一个特定的单词,它在文本文件中的行号和列号我试图找到并用字符替换该单词,例如:

鉴于文本文件包含以下内容(假设其位置如同显示 - 未写入 - 此处

  

兴奋的他现在自然而然地看到了通勤办公室。靠堆栈   是法院的希望。更进一步,所以朋友们要贬低。禁止关注   做私人的。顽固的居住,但男人全神贯注地害羞。假装上午   堆栈认真抵达公司等等。 Felicity通知但不得不这样做   严格承认如何叠加你。

并且,要替换的单词为stack,其中文本中的位置为行3和列16,请将其替换为字符*,< / p>

因此,在替换发生后,文本文件现在将具有以下内容:

  

兴奋的他现在自然而然地看到了通勤办公室。靠堆栈   是法院的希望。更进一步,所以朋友们要贬低。禁止关注   做私人的。顽固的居住,但男人全神贯注地害羞。假装上午   *认真抵达公司等。 Felicity通知但不得不这样做   严格承认如何叠加你。

我考虑过linecache,但对于大型文本文件来说效率似乎非常低效。另外,鉴于我已经有行号和列号,我希望有一种方法可以直接进入该位置并执行替换。

有没有人知道在Python中这样做的方法?

修改

使用numpy的genfromtxt提出的初始解决方案(很可能)在后续issue中的讨论之后不适合,因为需要文本文件的每一行都存在并且没有被跳过(例如空行,以'w'开头的字符串和'/ * .. /')中的字符串。

2 个答案:

答案 0 :(得分:2)

尝试这样的食谱:

import numpy as np
import os

def changethis(pos):
    # Notice file is in global scope
    appex = file[pos[1]-1][:pos[2]] + '*' + file[pos[1]-1][pos[2]+len(pos[0]):]
    file[pos[1]-1] = appex

pos = ('stack', 3, 16)
file = np.array([i for i in open('in.txt','r')]) #BEFORE EDIT: np.genfromtxt('in.txt',dtype='str',delimiter=os.linesep)
changethis(pos)
print(file)

结果如下:

[ 'Excited him now natural saw passage offices you minuter. At by stack being court hopes. Farther'
 'so friends am to detract. Forbade concern do private be. Offending residence but men engrossed'
 'shy. Pretend am * earnest arrived company so on. Felicity informed yet had to is admitted'
 'strictly how stack you.']

请注意,将一堆长字符串放入numpy数组并以某种方式更改它们有点骇人听闻,但在插入位置元组的较长循环时它应该是高效的。

编辑:由于@ user2357112让我意识到文件阅读器的选择不是最合适的(虽然它适用于有问题的练习),所以我编辑了这个答案以提供相同的the follow up question中给出的解决方案。

答案 1 :(得分:2)

考虑一行:

  

word1 a word2 a word3 a word4

如果您有这些更改:

[('word1', 1, 1), ('word2', 1, 9), ... ]

然后按顺序处理它们:

  

* word2 a word3 a word4

您将失败,因为当您将'word1'替换为较短的字符串'*'时,您正在更改单词的位置。

相反,您必须按行排序更改列表,按列反转:

changes = sorted(changes, key=lambda t: (t[1], -t[2]))

然后,您可以在遍历文件时处理更改,如@JRajan引用的链接所示:

with open("file", "r") as fp:
    fpline_text = enumerate(fp)
    fpline,text = next(fpline_text)

    for edit in changes:
        word,line,offset = edit
        line -=1  # 0 based

        while fpline < line:
            print(text)
            fpline,text = next(fpline_text)

        offset -= 1    # 0-based
        cand = text[offset:offset+len(word)]

        if cand != word:
            print("OOPS! Word '{}' not found at ({}, {})".format(*edit))
        else:
            text = text[0:offset]+'*'+text[offset+len(word):]

    # Rest of file
    try:
        while True:
            print(text)
            fpline,text = next(fpline_text)
    except StopIteration:
        pass