【问题标题】:Using list comprehension and a dict for regex substitution使用列表理解和 dict 进行正则表达式替换
【发布时间】:2016-04-08 04:43:30
【问题描述】:

以下 Python 3 代码循环遍历字符串列表并使用正则表达式替换每个字符串中的一些文本。

这里的字符串很简单,但在现实世界中它们可能更复杂且数量更多,因此我决定使用re.sub() 而不是str.replace()

all = ("this line has no hits",
       "a letter to tom from peter",
       "today bonny went to school",
       "harry made some cake")

for myitem in all:
    newitem = re.sub("harry","sally",myitem)
    newitem = re.sub("tom","jerry",newitem)
    newitem = re.sub("bonny","clyde",newitem)
    print(newitem)

这似乎按预期工作:

>>> this line has no hits
a letter to jerry from peter
today clyde went to school
sally made some cake
>>> 

在现实生活中会有大量的字符串,这会导致代码块混乱。我认为通过在dict 中定义正则表达式对并使用列表推导可能会有一种更简洁、更 Pythonic 的方式来做到这一点。所以我尝试了这个:

mydict = {'harry':'sally','tom':'jerry','bonny':'clyde'}

newall = [re.sub(i, mydict[i], j) for i in mydict for j in all]
print(newall)

这不起作用,因为它不会返回带有替换文本的字符串列表,但我不明白为什么它不起作用。

我的问题是:

  • 我在上面的例子中做错了什么?
  • 是否有更好的方法来解决涉及长字符串的大量替换问题?

(请注意,我可能错过了这里的明显内容,因为我只研究 Python 几天;我的背景是 R 和 Perl。)

【问题讨论】:

  • print(newall) 的输出是什么?
  • 没关系,您的解决方案所做的是all 中的项目和mydict 中的项目的某种笛卡尔积。查看解决方案的答案:)
  • 顺便说一句,all 是一个你可能不想覆盖的 python 内置函数。

标签: python regex python-3.x dictionary list-comprehension


【解决方案1】:

包含两个列表的列表推导很讨厌。它们容易出错且难以阅读。为什么不简单地使用两个循环?:

all = ("this line has no hits",
       "a letter to tom from peter",
       "today bonny went to school",
       "harry made some cake")

mydict = {'harry':'sally','tom':'jerry','bonny':'clyde'}

output = []
for line in all:
    for search, replace in mydict.items():
        line = re.sub(search, replace, line)
    output.append(line)

print(output)

['这条线没有命中','彼得给杰瑞的信','今天克莱德去上学了','莎莉做了一些蛋糕']

【讨论】:

  • 对。在这里与python2混合。现在应该没事了。
  • 我会将all 更改为其他名称,即built-in method 名称。
  • 我同意,但由于这似乎是一次性脚本,我想遵循 OP 的命名
【解决方案2】:

您需要使用另一个函数式编程概念,reduce。

您希望将 mydict 中的 每个 键值一个接一个地应用于同一字符串,从而产生 one,即最终字符串。在这种情况下(使用多值 dict/list/set 来获得单个答案),您可以使用 reduce。像这样:

import re

# copied from question
all = ("this line has no hits",
       "a letter to tom from peter",
       "today bonny went to school",
       "harry made some cake")

mydict = {'harry':'sally','tom':'jerry','bonny':'clyde'}

# define the function used in reduce
def replace_strings(line, mydictkey):
    return re.sub(mydictkey, mydict[mydictkey], line)

for line in all:
    print reduce(replace_strings, mydict.keys(), line)

并以列表理解形式:

newall = [reduce(replace_strings, mydict.keys(), line) for line in all]
print newall

函数式编程结构(归约、列表理解、过滤器)有一些很好的基础知识:https://docs.python.org/2/tutorial/datastructures.html#functional-programming-tools

【讨论】:

  • 感谢您的回答。我正在使用 Python 3,它似乎没有 reduce?
  • 嗯,看来你必须导入和使用 functools:docs.python.org/3.0/whatsnew/3.0.html 我想这是明确不推荐的,但我个人很喜欢 reduce
猜你喜欢
  • 2021-05-22
  • 2014-10-02
  • 1970-01-01
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 2014-03-29
  • 1970-01-01
相关资源
最近更新 更多