如何使用|进行正则表达式匹配?

3
import re
s6 = '''Male : abc
   Male : def'''
re.findall(r'(.*):|:(.*)', s6)

我的输出:

[('Male ', ''), ('            Male ', '')]

我的期望输出:

[('Male','abc'),('Male','def')]

当我使用re.findall(r'(.*):', s6)时,我得到的是['Male ', ' Male '],而当我使用re.findall(r':(.*)', s6)时,我得到的是[' abc', ' def']。当我使用|符号时,输出结果是错误的。
免责声明:请勿使用re.split 我已经使用了\w+也能够工作,但我想要一个以下格式的表达式。我已经使用了re.findall(r'\s*(\w+)\s*:|:\s*(\w+)', s6),但它不能单独工作。使用\s*(\w+)\s*::\s*(\w+)', s6时,它可以工作。
我想知道为什么使用|时它不能工作。
5个回答

4
交替运算符|表示“匹配此正则表达式,否则匹配那个正则表达式”。这两个子表达式无法同时匹配。如果第一个是匹配项,则第二个甚至不会被检查。
要从冒号的两侧提取内容,只需创建一个正则表达式,在同一匹配中捕获两侧的文本即可。
re.findall(r'([^\n:]+):([^\n:]+)', s6)

为了删除匹配结果周围的空白字符,你需要使用一个更加复杂的正则表达式,但是当你知道匹配字符串总是单个标记(即每个标记都是没有空格的单个字母字符串)时,也可以不必这样做。
re.findall(r'(\w+)\s*:\s*(\w+)', s6)

也许针对多个令牌尝试这样做:
re.findall(r'\s*([^\n:]+?)\s*:\s*([^\n:]+?)(?=\s*(?:\n|$))', s6)

我们在非贪婪匹配和贪婪匹配之间交替使用,以获得最短的符合正则表达式条件的字符串。

或者,您可以利用贪婪匹配的特性来使其为您所用:

re.findall(r'(\w+(?:[^\n\S]+\w+)*)\s*:\s*(\w+(?:[^\n\S]+\w+)*)', s6)

我们将尽可能多的空格分隔的标记捕获到匹配中,只要空格不包含换行符。

更详细地说,e+尽可能多地匹配(贪婪匹配),而e+?尽可能少地匹配(非贪婪吝啬匹配)。(?=...)是一个前瞻,它要求后面的表达式匹配,但不捕获或消耗匹配文本。因此,当将e(?=e)应用于文本eee时,它首先匹配初始的e,然后在下一次findall迭代中找到紧随其后的一个,即使它已经参与满足上一个匹配。当然,(?:...)是普通的非捕获组括号,[^\n\S]是一个字符类,它匹配任何一个不是换行符的字符,也不是空格类的成员 - 因此实际上是除了换行符之外的任何空格。

请注意,我们明确避免在捕获表达式中匹配冒号或换行符。

新手:“我怎么才能匹配所有这些字符串?”
大师:“我怎么只匹配这些字符串?”


1
感谢您回答这个问题。很少见到有人想要在这里学习,而我们中的一些人(环顾四周)只是发布复制粘贴的解决方案,忽略了它并没有回答他所问的问题。 - user1600649

2

这个不起作用是因为第一个匹配项消耗了锚点(冒号),所以第二个匹配项永远不会被匹配到。你需要使用断言来解决这个问题,但对于这种情况来说这样做太过复杂。

import re
compiled = re.compile(r'((\w+)\s*(?=:)|(?<=:)\s*(\w+))') 
s6 = '''Male : abc 
    Male : def''' 
re.findall(compiled, s6)                                                                                                                                                                            

# Output:
[('Male ', 'Male', ''),
 (' abc', '', 'abc'),
 ('Male ', 'Male', ''),
 (' def', '', 'def')]

现在您需要对已有的列表进行后处理,不建议使用此输入。简而言之:不要使用一个锚点来代替两种情况。


1
如果你需要所有的单词,只需使用'\w+'
s6 = '''Male : abc
   Male : def'''
re.findall('\w+', s6)

输出:

['Male', 'abc', 'Male', 'def']

1
我们可以尝试在一个或多个非单词字符上拆分您的字符串:
s6 = """Male : abc
Male : def"""
words = re.split(r'\W+', s6)
print(words)

['Male', 'abc', 'Male', 'def']

1
你只需匹配你所需的内容,
s6 = '''Male : abc
   Male : def'''
re.findall('[a-zA-Z]+', s6)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接