Как сопоставить любую строку из списка строк в регулярных выражениях в python?
Допустим, у меня есть список строк,
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.")
Каким будет правильный способ? Или нужно сделать несколько регулярных выражений и сопоставить их по отдельности с строкой?
Ответы
Ответ 1
string_lst = ['fun', 'dum', 'sun', 'gum']
x="I love to have fun."
print re.findall(r"(?=("+'|'.join(string_lst)+r"))",x)
Вы не можете использовать match
как оно будет совпадать с самого findall
Вместо этого используйте findall
.
Вывод: ['fun']
используя search
вы получите только первое совпадение. findall
этого используйте findall
.
Также используйте lookahead
если совпадающие совпадения не начинаются в одной и той же точке.
Ответ 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']
Ответ 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 answer решает проблему:
string_lst = ['fun', 'dum', 'sun', 'gum']
x="I love to have fun."
y="I love to have funny gum."
print(re.findall(r"(?=(\b" + '|'.join(string_lst) + r"\b))", x))
> ['fun']
print(re.findall(r"(?=(\b" + '|'.join(string_lst) + r"\b))", y))
> ['gum']