【问题标题】:How to match any string from a list of strings in regular expressions in python?如何匹配python中正则表达式中字符串列表中的任何字符串?
【发布时间】:2016-01-29 03:03:24
【问题描述】:

假设我有一个字符串列表,

string_lst = ['fun', 'dum', 'sun', 'gum']

我想创建一个正则表达式,在其中的某个点,我可以匹配我在该列表中的任何字符串,在一个组内,例如:

import re
template = re.compile(r".*(elem for elem in string_lst).*")
template.match("I love to have fun.")

这样做的正确方法是什么?还是必须制作多个正则表达式并将它们分别与字符串匹配?

【问题讨论】:

  • |为胶水连接数组元素,将形成字符串fun|dum|sun|gum,可用于正则表达式。
  • re.search('|'.join(string_lst), input_string)
  • any(z in string_list for z in re.findall(r"['\w]+", 'This is just for fun'))
  • 您关心找到了哪些字符串,还是只关心找到了其中的任何一个?
  • 答案还可以,但不是最佳答案,您的问题是指要自动查找正则表达式 r"[fs]un|[dg]u[m]" 吗?这是一个非常有趣的问题,顺便说一句,它是音韵学等领域的基础,但我需要知道你是否打算解决这个问题以及你可以假设相似的长度或至少在插入删除和替换之间进行一些权衡,在什么术语是最小的正则表达式,诸如此类的东西。

标签: python regex string python-3.x


【解决方案1】:

在管道字符|上加入列表,表示正则表达式中的不同选项。

string_lst = ['fun', 'dum', 'sun', 'gum']
x="I love to have fun."

print re.findall(r"(?=("+'|'.join(string_lst)+r"))", x)

输出:['fun']

您不能使用match,因为它会从一开始就匹配。 使用search 你只会得到第一场比赛。所以请改用findall

如果您的重叠匹配不是从同一点开始,也请使用 lookahead

【讨论】:

  • 但是如果有类似funny这样的词,这将返回['fun']
  • 哦,太好了。 re.findall(r"(?=\b("+'|'.join(string_lst)+r")\b)",x) 它对我有用
  • 该方法是正确的,但未能做到完整。它将匹配给定字符串中列表单词的每次出现,即使是单词的一部分相似的单词。例如,尝试给予,x =“我喜欢有趣”并检查。正确的原始格式是: print(re.findall(r"(?=(\b" + '|'.join(string_lst) + r"\b))", x))
  • @Pranzell 我删除了您的编辑。请在现有答案下方添加您的答案,说明更好的条件:)
【解决方案2】:

regex module命名列表(实际设置):

#!/usr/bin/env python
import regex as re # $ pip install regex

p = re.compile(r"\L<words>", words=['fun', 'dum', 'sun', 'gum'])
if p.search("I love to have fun."):
    print('matched')

这里words只是一个名字,你可以使用任何你喜欢的名字。
.search()方法用于代替.*在命名列表之前/之后。

使用 stdlib 的 re 模块模拟命名列表:

#!/usr/bin/env python
import re

words = ['fun', 'dum', 'sun', 'gum']
longest_first = sorted(words, key=len, reverse=True)
p = re.compile(r'(?:{})'.format('|'.join(map(re.escape, longest_first))))
if p.search("I love to have fun."):
    print('matched')

re.escape() 用于转义单个单词中的正则表达式元字符,例如 .*?(以匹配单词的字面意思)。
sorted() 模拟 regex 行为,它将最长的单词放在首位替代品,比较:

>>> import re
>>> re.findall("(funny|fun)", "it is funny")
['funny']
>>> re.findall("(fun|funny)", "it is funny")
['fun']
>>> import regex
>>> regex.findall(r"\L<words>", "it is funny", words=['fun', 'funny'])
['funny']
>>> regex.findall(r"\L<words>", "it is funny", words=['funny', 'fun'])
['funny']

【讨论】:

  • 你可以补充说它解决了a|b|c|d ...方法的复杂性问题(线性搜索)
【解决方案3】:

除了正则表达式,你可以使用列表推导,希望不要跑题。

import re
def match(input_string, string_list):
    words = re.findall(r'\w+', input_string)
    return [word for word in words if word in string_list]

>>> string_lst = ['fun', 'dum', 'sun', 'gum']
>>> match("I love to have fun.", string_lst)
['fun']

【讨论】:

    【解决方案4】:

    您应该确保在组合成正则表达式之前正确转义字符串

    >>> import re
    >>> string_lst = ['fun', 'dum', 'sun', 'gum']
    >>> x = "I love to have fun."
    >>> regex = re.compile("(?=(" + "|".join(map(re.escape, string_lst)) + "))")
    >>> re.findall(regex, x)
    ['fun']
    

    【讨论】:

      【解决方案5】:

      与@vks 回复一致-我觉得这实际上完成了任务...

      finds = re.findall(r"(?=(\b" + '\\b|\\b'.join(string_lst) + r"\b))", x)
      

      添加单词边界完成任务!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-19
        • 2013-08-02
        • 1970-01-01
        • 2011-11-08
        • 2015-04-26
        • 1970-01-01
        相关资源
        最近更新 更多