我有这段代码可以找到以@或#,
开头的单词p = re.findall(r'@\w+|#\w+', str)
现在让我感到烦恼的是重复\ w +。我确信有办法做一些像
这样的事情p = re.findall(r'(@|#)\w+', str)
这会产生相同的结果但不会产生相反的效果,而只返回#
和@
。如何改变正则表达式以便我不重复\w+
?这段代码很接近,
p = re.findall(r'((@|#)\w+)', str)
但它返回[('@many', '@'), ('@this', '@'), ('#tweet', '#')]
(注意额外的'@','@'和'#'。
另外,如果我重复这个re.findall
代码500,000次,这可以编译成一个模式然后更快吗?
答案 0 :(得分:10)
您有两种选择:
(?:@|#)\w+
[@#]\w+
findall
您遇到的问题是findall
返回匹配的方式取决于存在多少个捕获组。
让我们仔细看看这个模式(注释显示组):
((@|#)\w+)
|\___/ |
|group 2 | # Read about groups to understand
\________/ # how they're defined and numbered/named
group 1
捕获组允许我们将子模式中的匹配保存在整体模式中。
p = re.compile(r'((@|#)\w+)')
m = p.match('@tweet')
print m.group(1)
# @tweet
print m.group(2)
# @
现在让我们来看看re
模块的Python文档:
findall
:返回字符串中pattern的所有非重叠匹配,作为字符串列表。从左到右扫描字符串,并按找到的顺序返回匹配项。如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,这将是一个元组列表。
这解释了您获得以下内容的原因:
str = 'lala @tweet boo #this &that @foo#bar'
print(re.findall(r'((@|#)\w+)', str))
# [('@tweet', '@'), ('#this', '#'), ('@foo', '@'), ('#bar', '#')]
根据规定,由于模式具有多个组,findall
将返回元组列表,每个匹配一个。每个元组都会为您提供给定匹配的组所捕获的内容。
该文档还解释了为什么要获得以下内容:
print(re.findall(r'(@|#)\w+', str))
# ['@', '#', '@', '#']
现在模式只有一个组,findall
返回该组的匹配列表。
相比之下,上面作为解决方案提供的模式没有任何捕获组,这就是为什么它们按照您的期望工作的原因:
print(re.findall(r'(?:@|#)\w+', str))
# ['@tweet', '#this', '@foo', '#bar']
print(re.findall(r'[@#]\w+', str))
# ['@tweet', '#this', '@foo', '#bar']