【问题标题】:Multiple strings replacement from dictionary字典中的多个字符串替换
【发布时间】:2021-11-16 03:24:05
【问题描述】:

我将创建一个脚本,该脚本将从字典中获取键和值,并将其用于替换一组文件。 如果在文件中找到“target_value”,我需要将“foo”替换为“foo1”。有许多不同的foo。所以,我猜字典会适合那个。

我从简单的事情开始:

    with fileinput.FileInput(filelist, inplace=True) as file:
        for line in file:
            if line.find('target_value'):
                print(line.replace("foo", "foo1"), end='')

由于某种原因,此脚本只是忽略 line.find 并用最后一行代码替换所有内容。 你能帮忙吗?

【问题讨论】:

  • target_value 在这里做什么?
  • 我在将“foo”替换为“foo1”时依赖它
  • 为什么不直接使用in 而不是str.find
  • line.find() 返回子字符串的索引,如果没有找到则返回-1-1 是真实的,所以即使没有找到目标值,你也要进行替换。唯一的错误整数是0,因此只要行不以target_value 开头,您就可以进行替换。
  • 另外,您想测试target_value 是在文件中的任何位置,还是只是每一行?

标签: python string replace


【解决方案1】:

如果找不到该值,Python 的 find 命令返回 -1,因此您需要类似以下内容:

with fileinput.FileInput(filelist, inplace=True) as file:
    for line in file:
        if line.find('target_value') > -1:
            line = line.replace("foo", "foo1")
        print(line, end='')

【讨论】:

    【解决方案2】:

    str.find 的问题在于它返回了"target_value"line 中出现的索引,因此是从0 到len(line)-len(target_value)-1 的任何整数。也就是说,除非"target_value" 不存在于line 中;然后str.find 返回-1bool(-1) 的值是True。事实上,line.find('target_value') 唯一一次是False"target_value"line 的第一部分。

    有几个选项:

    with fileinput.FileInput(filelist, inplace=True) as file:
        for line in file:
            if line.find('target_value') != -1:
                print(line.replace("foo", "foo1"), end='')
    

    或者:

    with fileinput.FileInput(filelist, inplace=True) as file:
        for line in file:
            if 'target_value' in line:
                print(line.replace("foo", "foo1"), end='')
    

    line 很长并且"target_value" 不在line 的开头出现时,第二个选项更具可读性并且往往表现更好。

    >>> timeit('"target_value" in s', setup='s = "".join("foobar baz" for _ in range(100))+"target_value"+ "".join("foobar baz" for _ 在范围内 (100))') 0.20444475099975534 >>> timeit('s.find("target_value") != -1', setup='s = "".join("foobar baz" for _ in range(100))+"target_value"+ ""。 join("foobar baz" for _ in range(100))') 0.30517548999978317

    【讨论】:

      【解决方案3】:

      您可以使用if 'target_value' in line: 代替.find(),它更具表现力且不涉及返回值约定。

      如果您有多个目标关键字(每个目标有多个替换),您可以像这样构建您的字典

      replacements = { 'target_value1': [('foo','foo1'), ('bar','bar1')],
                       'target_value2': [('oof','oof'), ('rab','rab2')],
                       'target_value3': [('foobar','foosy'),('barfoo','barry')]}
      

      然后找出存在哪些目标值并执行相应的替换:

      with open(fileName,'r') as f:
           content = f.read()
           for target,maps in replacements.items(): # go through target keywords
               if target not in content: continue   # check target (whole file)
               for fromString,toString in maps:     # perform replacements for target
                   content = content.replace(fromString,toString)
      
      # you probably want to save the new content at this point
      with open(fileName,'w') as f:
          f.write(content)
      

      请注意,在此示例中,我假设目标关键字标记了整个文件(而不是每一行)。如果目标关键字特定于每一行,则需要将内容分解为行并将逻辑放在行上的循环中以逐行执行替换

      您实际上并不需要将替换数据作为字典(第二个示例使用行级单目标替换):

      replacements = [ ['target_value1',('foo','foo1'), ('bar','bar1')],
                       ['target_value2',('oof','oof'), ('rab','rab2')],
                       ['target_value3',('foobar','foosy'),('barfoo','barry')]]
      
      with open(fileName,'r') as f:
           lines = f.read().split("\n")
           for i,line in enumerate(lines):          # for each line
               for target,*maps in replacements:    # go through target keywords
                   if target not in line: continue  # check target (line level)
                   for fromString,toString in maps: # perform replacements on line
                       lines[i] = lines[i].replace(fromString,toString)
                   break # only process one keyword per line
      
      # to save changes
      with open(fileName,'w') as f:
          f.write("\n".join(lines)) 
      

      【讨论】:

        猜你喜欢
        • 2013-11-18
        • 2022-11-10
        • 2019-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多