使用交替运算符匹配多个正则表达式模式?

16

我在使用Python正则表达式时遇到了一个小问题。

假设这是输入:

(zyx)bc

我想达到的目的是将括号内的内容作为一个单独的匹配项,括号外的每个字符都作为一个单独的匹配项。期望的结果类似于:

['zyx','b','c']

匹配的顺序应该保持不变。

我尝试使用Python 3.3实现,但是好像无法找到正确的正则表达式。目前我有:

matches = findall(r'\((.*?)\)|\w', '(zyx)bc')

print(matches)会产生以下输出:

['zyx','','']

有什么想法我做错了吗?


这只是一个示例输入。正则表达式应该能够区分不同的情况,例如(ab)(bc)(ca),abc,(abc)(abc)(abc)或(zyx)bc等,同时识别哪些字符在括号内,哪些不在。 - Julian Laval
5个回答

24

根据re.findall的文档:

如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,则这将是元组的列表。

虽然您的正则表达式已经匹配字符串三次,但在后两次匹配中,(.*?)组为空。如果您想要另一半正则表达式的输出,可以添加第二个组:

>>> re.findall(r'\((.*?)\)|(\w)', '(zyx)bc')
[('zyx', ''), ('', 'b'), ('', 'c')]

或者,您可以删除所有的分组以再次获得简单的字符串列表:

>>> re.findall(r'\(.*?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']

但您需要手动删除括号。


1
FYI:感谢您的回答。要去掉括号,请使用以下代码:'matches = [match.strip('()') for match in findall(r'(.*?)|\w', case)]' - Julian Laval

7
其他答案已经向您展示了如何获得所需的结果,但需要额外手动删除括号。如果您在正则表达式中使用lookaround,就不需要手动去除括号:
>>> import re
>>> s = '(zyx)bc'
>>> print (re.findall(r'(?<=\()\w+(?=\))|\w', s))
['zyx', 'b', 'c']

解释:

(?<=\() // lookbehind for left parenthesis
\w+     // all characters until:
(?=\))  // lookahead for right parenthesis
|       // OR
\w      // any character

很好的想法。但是如果我想按照我想要的顺序逐个进行3个正则表达式替换,该如何在一些 .txt 文件中实现呢? - Just Me

4
让我们使用 re.DEBUG 查看输出。
branch 
  literal 40 
  subpattern 1 
    min_repeat 0 65535 
      any None 
  literal 41 
or
  in 
    category category_word

糟糕,这里只有一个子模式,但是如果没有子模式的话re.findall并不会提取出任何子模式

a = re.findall(r'\((.*?)\)|(.)', '(zyx)bc',re.DEBUG); a
[('zyx', ''), ('', 'b'), ('', 'c')]
branch 
  literal 40 
  subpattern 1 
    min_repeat 0 65535 
      any None 
  literal 41 
or
  subpattern 2 
    any None

更好了。 :)
现在我们只需要将它转换成您想要的格式即可。
[i[0] if i[0] != '' else i[1] for i in a]
['zyx', 'b', 'c']

2
文档提到要特殊处理组,因此不要在括号模式周围放置组,这样你将得到所有内容,但需要自己从匹配的数据中删除括号。
>>> re.findall(r'\(.+?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']

或者使用更多的组,然后处理得到的元组以获得您要查找的字符串:
>>> [''.join(t) for t in re.findall(r'\((.+?)\)|(\w)', '(zyx)bc')]
>>> ['zyx', 'b', 'c']

1
In [108]: strs="(zyx)bc"

In [109]: re.findall(r"\(\w+\)|\w",strs)
Out[109]: ['(zyx)', 'b', 'c']

In [110]: [x.strip("()") for x in re.findall(r"\(\w+\)|\w",strs)]
Out[110]: ['zyx', 'b', 'c']

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