簡體   English   中英

當我的模式只包含一個組時,為什么 re.findall 返回一個元組列表?

[英]Why does re.findall return a list of tuples when my pattern only contains one group?

假設我有一個包含字母和兩個分隔符12的字符串s 我想按以下方式拆分字符串:

  • 如果子串t介於12之間,則返回t
  • 否則,返回每個字符

因此,如果s = 'ab1cd2efg1hij2k' ,則預期輸出為['a', 'b', 'cd', 'e', 'f', 'g', 'hij', 'k']

我嘗試使用正則表達式:

import re
s = 'ab1cd2efg1hij2k'
re.findall( r'(1([a-z]+)2|[a-z])', s )

[('a', ''),
 ('b', ''),
 ('1cd2', 'cd'),
 ('e', ''),
 ('f', ''),
 ('g', ''),
 ('1hij2', 'hij'),
 ('k', '')]

從那里我可以做[ x[x[-1]!=''] for x in re.findall( r'(1([az]+)2|[az])', s ) ]得到我的答案,但我仍然不明白輸出。 文檔說,如果模式有多個組, findall返回一個元組列表。 但是,我的模式只包含一組。 歡迎任何解釋。

你的模式有兩個組,更大的組:

(1([a-z]+)2|[a-z])

和第二個較小的組,它是您的第一組的子集

([a-z]+)

這是一個可以為您提供預期結果的解決方案,盡管請注意,它真的很丑陋,並且可能有更好的方法。 我就是想不通:

import re
s = 'ab1cd2efg1hij2k'
a = re.findall( r'((?:1)([a-z]+)(?:2)|([a-z]))', s )
a = [tuple(j for j in i if j)[-1] for i in a]

>>> print a
['a', 'b', 'cd', 'e', 'f', 'g', 'hij', 'k']

您的正則表達式有 2 組,只需查看您使用的括號數量:)。 一組是([az]+) ,另一組是(1([az]+)2|[az]) 關鍵是您可以在其他組中擁有組。 因此,如果可能,您應該構建一個只有一組的正則表達式,這樣您就不必對結果進行后處理。

只有一組的正則表達式示例如下:

>>> import re
>>> s = 'ab1cd2efg1hij2k'
>>> re.findall('((?<=1)[a-z]+(?=2)|[a-z])', s)
['a', 'b', 'cd', 'e', 'f', 'g', 'hij', 'k']

我參加聚會晚了 5 年,但我想我可能已經找到了一個優雅的解決方案來解決 re.findall() 帶有多個捕獲組的丑陋的元組輸出。

一般來說,如果你最終得到一個看起來像這樣的輸出:

[('pattern_1', '', ''), ('', 'pattern_2', ''), ('pattern_1', '', ''), ('', '', 'pattern_3')]

然后你可以用這個小技巧把它變成一個平面列表:

["".join(x) for x in re.findall(all_patterns, iterable)]

預期的輸出將是這樣的:

['pattern_1', 'pattern_2', 'pattern_1', 'pattern_3']

它在 Python 3.7 上進行了測試。 希望能幫助到你!

查看類似問題的答案: https ://bugs.python.org/issue6663 如果您使用的是 findall,請去掉括號:

import re
s = 'ab1cd2efg1hij2k'
re.findall( r'(?<=1)[a-z]+(?=2)|[a-z]', s )

如果您想在不拆分為匹配組的情況下進行 'or' 匹配,只需在 'or' 匹配的開頭添加一個 '?:'。

沒有 '?:'

re.findall('(test (word1|word2))', 'test word1')

Output:
[('test word1', 'word1')]

和 '?:'

re.findall('(test (?:word1|word2))', 'test word1')

Output:
['test word1']

進一步說明: https : //www.ocpsoft.org/tutorials/regular-expressions/or-in-regex/

只需要做一個簡單的更改:將組更改為非捕獲組

代碼:

import re
s = 'ab1cd2efg1hij2k'
re.findall( r'(1(?:[a-z]+)2|[a-z])', s )

輸出:

['a', 'b', '1cd2', 'e', 'f', 'g', '1hij2', 'k']

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM