簡體   English   中英

Python從列表中獲取所有正則表達式匹配組

[英]Python get all regexp matching groups from a list

假設我已經閱讀了一個文本文件的所有行,如下所示:

ifile = open('myfile.txt')
lines = ifile.readlines()

現在,假設我有以下正則表達式:

rgx = re.compile(r'Found ([0-9]+) solutions')

我可以用

result = filter(rgx.match,lines)
print result

獲取匹配列表,但我想要的是匹配組列表。 例如,而不是像這樣的輸出:

Found 3 solutions
Found 35 solutions
Found 0 solutions

我想要這樣的輸出:

3
35
0

我怎樣才能做到這一點?

import re

rgx = re.compile(r'Found ([0-9]+) solutions')

with open('myfile.txt') as f:
    result = [m.group(1) for m in (rgx.match(line) for line in f) if m]

內部循環(rgx.match(line) for line in f)是一個生成器表達式,其作用類似於apply() 對於文件中的每一行,它調用rgx.match()並產生結果,一個SRE_Match對象(我通常稱之為“匹配對象”)。

外部循環具有if m ,它丟棄任何不評估為 true 的re.match()當模式不匹配時, re.match()返回None )。 然后m.group(1)使用匹配對象從括號內獲取文本。 有關詳細信息,請參閱re模塊的文檔。 由於外部循環是列表推導式的一部分,因此會構建並返回結果列表。

由於前綴和后綴是固定字符串,您可以使用環視:

r'(?<=Found )\d+(?= solutions)'

不過,我認為應該有某種方法可以使用正則表達式來完成這項工作。

您可以從 match 命令返回“匹配”對象(除非您使用過濾器將其隱式轉換為字符串),唉。 沒有像樣的文檔可以通過。 ipython 幫助但它在線: http ://docs.python.org/3/library/re.html#match-objects

例如。

for line in lines:
  result = rgx.match(line)
  if not result: continue
  print result.group(1)
print '\n'.join([m.group(1) for l in lines for m in [rgx.search(l)] if m])

所以這里提供的其他解決方案很好,可能是最易讀的,但是在您需要的具體示例中,我建議有幾個單行替代方案(當然要記住,您的問題來自 2013 年,您可能不要在同一家公司工作,更不用說在同一個項目上工作了)。 我還認為,如果有人在這里發現自己,這會引起普遍的興趣。 因為您的前提非常簡單(每行一個有趣的數據),您可以執行以下操作:

>>> # simulate reading the (hopefully not ginormous) file into a single string
>>> lines = "Found 3 solutions\nFound 35 solutions\nFound 0 solutions\n"
>>> # we're now in the state we would be after "lines = file.readlines()"
>>> print(lines)
Found 3 solutions
Found 35 solutions
Found 0 solutions

>>> # we're so constrained, we can get away with murder in a single line
>>> solution_counts = re.findall(r'\d+', file_contents)
>>> solution_counts
['3', '35', '0']
>>> # bazinga!

這是一個令人驚訝的強大解決方案。 如果您的文件的本地化方式將“找到”和“解決方案”這兩個詞更改為翻譯后的等價詞,則只要格式保持不變,此解決方案就無關緊要。 不包含十進制整數的頁眉和頁腳? 不在乎。 它可以處理單個字符串,例如"Found solution sets of count 3, 35, and 0" 。完全相同的代碼將提取您想要的答案。 但是,更常見的是您知道格式,但無法控制它,並且每行/記錄都充滿異構數據,並且您關心的部分被其他您可能關心或可能不關心的部分包圍。 因此,請考慮以下古怪的變體:

file_contents = "99 bottles of beer on the wall\n" \
                "50 ways to leave your lover\n" \
                "6 kinds of scary\n" \
                "Found 3 solutions of type A\n" \
                "Found 35 solutions of type C\n" \
                "Found 4 solutions of unknown type\n" \
                "2 heads are better than 1\n" \
                "etc, ...\n"

我們天真的解決方案將返回['99', '50', '6', '3', '35', '4', '2', '1'] ,除非您知道如何,否則這並不是那么有趣過濾掉無關的數據,如此混亂、容易出錯和脆弱——五顆星中的一顆。 這會很容易,而且可能是很好的干凈解決方案,涉及迭代行而不是將整個字節流攝取到內存中,但讓我們堅持假設我們出於某種原因必須這樣做。 也許它不是來自文件(從 TCPIP 流或其他文件中捕獲。使用另一個單行, lines.split('\\n') ,我們再次將行分開(沒有換行符),並且可以迭代並執行理解等,但我們也可以使用finditer跳到它

>>> [ m.group(1) for m in re.finditer(r'Found (\d+)', file_contents) ]
>>> ['3', '35', '4']

相當健壯。 我什至不確定預編譯是否更快,除非您正在處理大量噩夢文件。

暫無
暫無

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

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