python中的正则表达式,这可以改进吗?

tip*_*ipu 2 python regex

我有这段代码可以找到以@或#开头的单词,

p = re.findall(r'@\w+|#\w+', str)
Run Code Online (Sandbox Code Playgroud)

现在让我烦恼的是重复\ w +.我确信有办法做某事

p = re.findall(r'(@|#)\w+', str)
Run Code Online (Sandbox Code Playgroud)

这将产生相同的结果,但它没有,它只返回#@.如何改变正则表达式以便我不重复\w+?这段代码很接近,

p = re.findall(r'((@|#)\w+)', str)
Run Code Online (Sandbox Code Playgroud)

但它返回[('@many', '@'), ('@this', '@'), ('#tweet', '#')](注意额外的'@','@'和'#'.

另外,如果我重复这段re.findall代码500,000次,这可以编译成一个模式然后更快吗?

pol*_*nts 10

解决方案

您有两种选择:

  • 使用非捕获组: (?:@|#)\w+
  • 甚至更好,一个角色类: [@#]\w+

参考


理解 findall

您遇到的问题是由于findall返回匹配的方式取决于存在多少个捕获组.

让我们仔细看看这个模式(注释显示组):

((@|#)\w+)
|\___/   |
|group 2 |     # Read about groups to understand
\________/     # how they're defined and numbered/named
 group 1
Run Code Online (Sandbox Code Playgroud)

捕获组允许我们将子模式中的匹配保存在整体模式中.

p = re.compile(r'((@|#)\w+)')
m = p.match('@tweet')
print m.group(1)
# @tweet
print m.group(2)
# @
Run Code Online (Sandbox Code Playgroud)

现在让我们来看看该re模块的Python文档:

findall:返回字符串中pattern的所有非重叠匹配,作为字符串列表.从左到右扫描字符串,并按找到的顺序返回匹配项.如果模式中存在一个或多个组,则返回组列表; 如果模式有多个组,这将是一个元组列表.

这就解释了为什么你得到以下内容:

str = 'lala @tweet boo #this &that @foo#bar'

print(re.findall(r'((@|#)\w+)', str))
# [('@tweet', '@'), ('#this', '#'), ('@foo', '@'), ('#bar', '#')]
Run Code Online (Sandbox Code Playgroud)

如指定的那样,由于模式具有多个组,因此findall返回元组列表,每个匹配一个.每个元组都会为您提供给定匹配的组所捕获的内容.

该文档还解释了为什么您获得以下内容:

print(re.findall(r'(@|#)\w+', str))
# ['@', '#', '@', '#']
Run Code Online (Sandbox Code Playgroud)

现在模式只有一个组,并findall返回该组的匹配列表.

相比之下,上面给出的解决方案模式没有任何捕获组,这就是为什么它们按照您的期望工作的原因:

print(re.findall(r'(?:@|#)\w+', str))
# ['@tweet', '#this', '@foo', '#bar']

print(re.findall(r'[@#]\w+', str))
# ['@tweet', '#this', '@foo', '#bar']
Run Code Online (Sandbox Code Playgroud)

参考

附件

  • @tipu - '任何'都可以编译/重用,不要忘记接受答案 (2认同)