【问题标题】:Search and replace string inside .txt file with user input使用用户输入搜索和替换 .txt 文件中的字符串
【发布时间】:2019-05-19 09:16:49
【问题描述】:

背景:我正在尝试自动化工作流程的某些部分。我采取的手动步骤:我得到一张在文本文件中更改 ID 的票。我必须通过网络共享文件夹,创建文件的备份,将复制的文件推送到存档文件夹中,并使用票证中的 ID 编辑现有文件。

我要创建的内容:一个小程序会询问我要更改的 ID(文本文件中有预先存在的 ID),然后它将进入文件中并找到匹配项。然后我希望程序问我要将 ID 更改为什么。我希望程序用我的输入编辑现有文件,保存它,然后关闭它。

到目前为止,我有以下代码来完成第一部分(复制文件并将其推送到存档文件夹中)。我有我坚持的第二个功能。我知道第二个功能不起作用,但希望其他人就他们认为我应该尝试的内容提供意见。我看过 fileinput 模块,但我读到它不是最好的模块,我应该尝试在没有 fileinput 模块的情况下对其进行编程。

代码

import shutil
import datetime
import os
import fileinput

original_file = "\\network\\path\\to\\file"

def date_rename_file():
    todays_date = datetime.datetime.now()
    stripped_time = todays_date.strftime('%Y%m%d')    
    shutil.copyfile(original_file, "\\network\\path\\to\\backupfolder\\device_"+str(stripped_time)+".txt")

def device_id_replace():
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(original_file, 'w') as devicetxt:
        for line in devicetxt:
            print(line)
            if original_id in line:
                print("Found "+original_id)

date_rename_file()
device_id_replace()

谢谢,请随意拆除我的代码 :) 我仍在学习中,如果有任何意见,我将不胜感激。另外,如果我遗漏了任何相关信息,请随时告诉我!

【问题讨论】:

  • 欢迎来到 StackOverflow。请按照您创建此帐户时的建议阅读并遵循帮助文档中的发布指南。 Minimal, complete, verifiable example 适用于此。在您发布 MCVE 代码并准确描述问题之前,我们无法有效地帮助您。我们应该能够将您发布的代码粘贴到文本文件中并重现您描述的问题。 StackOverflow 不是编码、评论或教程资源。
  • 最重要的是,“我被卡住了”和“不工作”不是问题规范。

标签: python string search replace user-input


【解决方案1】:

你可以试试这个:

def device_id_replace():
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(original_file, 'r+') as devicetxt: #r+ is for read and write
        string = devicetxt.read() #read into one string
        string = string.replace(original_id, new_id) #replacement
        devicetxt.truncate(0) #To clear contents of file before writeback
        devicetxt.seek(0) #Put the file's current position at 0
        devicetxt.write(string) #writeback to file

此外,最好将original_file 作为字符串传递给函数。请参阅下面的编辑代码:

import shutil
import datetime
import os
import fileinput

original_file = "\\network\\path\\to\\file"

def date_rename_file(filepath):
    todays_date = datetime.datetime.now()
    stripped_time = todays_date.strftime('%Y%m%d')    
    shutil.copyfile(filepath, "\\network\\path\\to\\backupfolder\\device_"+str(stripped_time)+".txt")

def device_id_replace(filepath):
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(filepath, 'r+') as devicetxt: #r+ is for read and write
        string = devicetxt.read() #read into one string
        string = string.replace(original_id, new_id) #replacement
        devicetxt.truncate(0) #To clear contents of file before writeback
        devicetxt.seek(0) #Put the file's current position at 0
        devicetxt.write(string) #writeback to file

date_rename_file(original_file)
device_id_replace(original_file)

【讨论】:

  • 谢谢你!这似乎主要工作,但我相信它将所有内容添加回同一个文件,所以我得到重复的数据。要去努力解决这个问题。不过谢谢,正是我想要的。
  • @ZookiePookie 感谢您发现这一点。我添加了一个额外的行devicetxt.truncate(0) 来解决这个问题。它将在写回之前清除所有内容,以免您获得重复数据。让我知道它是否有帮助。从功能上讲,最好在 for 循环中打开一次文件并进行读/写,而不是在 2 个 for 循环中分别打开两次以进行读取然后写入。
  • 所以我在我的代码中尝试了新的截断。它不会创建很好的重复项,但会在文本文件的顶部添加大量空白。我将尝试调试导致该问题的步骤。谢谢!
  • 如果您有时间可以解释一下您在此处所做的评论:“另外,最好将 original_file 作为字符串传递给函数。请参阅下面的编辑代码:”我试图理解为什么我们将参数传递给函数。另外,“文件路径”参数来自哪里?您可以将任何阅读内容发送给我以更好地理解这一点?
  • @ZookiePookie 为了解决空白问题,我添加了.seek(0) 将光标设置在文件的 0 位置。抱歉,我在测试期间错过了这一点。发生的情况是 .truncate(0) 从 0 位置删除所有内容,但光标仍位于它的最后位置。所以.seek(0) 解决了这个问题。
【解决方案2】:

试试这个:

original_file = ""\\network\\path\\to\\file""

def device_id_replace(filepath):                   
    original_id = input("What device ID are you needing to replace?") 
    new_id = input("What is the new device ID?")   
    with open(filepath, 'r') as devicetxt:
        new_content = []
        for line in devicetxt:
            new_content.append(line.replace(original_id, new_id))
    with open(filepath, "w") as devicetxt:
        for line in new_content:
            devicetxt.write(line)

device_id_replace(original_file)

@ycx 的答案在过去不起作用。所以我修复了你的旧代码:

original_file = "test.txt"


def device_id_replace(filepath):
    original_id = input("What device ID are you needing to replace?")
    new_id = input("What is the new device ID?")
    with open(filepath, 'r+') as devicetxt: #r+ is for read and write
        contents = devicetxt.readlines() #put all lines into a list
        for line_i, line in enumerate(contents):
            if original_id in line:
                contents[line_i] = line.replace(original_id, new_id) # CHANGED LINE
        devicetxt.truncate(0)
        devicetxt.seek(0)
        devicetxt.writelines(contents) #writeback to file

device_id_replace(original_file)

【讨论】:

  • 也试过了!使我免于对 ycx 的建议进行故障排除。非常感谢您的帮助!这是我想要的工作!我看到有一个空列表,我们将每一行都附加到其中,我们实质上是将每一行重写到同一个文件中吗?
  • 带 open(..., 'r')... 的代码块读取文件,带 open(..., "w")... 的代码块覆盖旧文件.也可以打开文件一次,用“r+”参数重写。
  • @ZookiePookie 你对代码感兴趣吗,它打开文件一次并直接替换?如果是的话,我也希望它能解决这个问题。
  • 感谢您为我调查。您的方法有效,@ycx 方法也有效。我想让你看看 ycx 的方法,因为它只有一个 for 循环,使代码更具可读性和简洁性,从我目前所学到的知识来看,这是“python zen”的一部分。
  • 我认为您对 ycx 的方法是正确的。当我运行它时,我没有看到任何替换发生。我正在尝试在“for line in devicetxt:”下方添加一个 if 语句。我希望 if else 说'if original_id in line:' 'print("Found " + original_id)' 然后执行 'new_content.append(line.replace(original_id, new_id))'。 'else:' 'print("请确保 PC ID 输入正确").但是,当我这样做时,它总是直接进入代码的“其他”部分。知道为什么它没有按预期工作吗?
【解决方案3】:

您有几个选择,如果您使用的是 Unix/Unix 之类的内部工具,则使用 sed 之类的内部工具,或者在旧文件的基础上创建一个新文件。

  1. 读取所有文件。
  2. 替换匹配项。
  3. 重写所有行。

这是一个pythonic版本

with open(filepath) as f:
    transformedLines = [line.replace(old, new) if (old in line) else (line) for line in f]
with open(filepath, 'w') as f:
    f.writelines(transformedLines);

一个不那么 Pythonic 的版本是类似的:

transformedLines = []
with open(filepath) as f:
    for line in f:
        if old in line:
            transformedLines.append(line.replace(old, new))
        else:
            transformedLines.append(line)

一种功能性的方式(虽然效率很低)可以用map来完成:

    transformedLines = list(map(lambda line : line.replace(old, new), f.readlines()))

如果您的文件不是很大,这应该没问题,否则您将不得不考虑使用不同类型的数据存储,例如数据库。

您的方法目前运行良好,但您希望以读取模式打开它,每行将其附加到一个新列表中,如果找到您的 id 则附加新行。

将新数组写入以写入模式打开的文件中,这将清除内容。

【讨论】:

  • 很好的建议 - 我会试试这个。我尝试了@ycx 方法,它似乎接近我想要的,但我相信它正在更新 ID,然后它再次将读取的所有内容写入文件,所以我得到了重复的数据。
  • 我添加了一些细节
猜你喜欢
  • 2014-02-06
  • 1970-01-01
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 2021-09-23
  • 1970-01-01
  • 2020-05-12
相关资源
最近更新 更多