簡體   English   中英

python regex:捕獲包含空格的多個字符串的一部分

[英]python regex: capture parts of multiple strings that contain spaces

我正在嘗試從看起來類似於的字符串中捕獲子字符串

'some string, another string, '

我希望結果匹配組為

('some string', 'another string')

我目前的解決方案

>>> from re import match
>>> match(2 * '(.*?), ', 'some string, another string, ').groups()
('some string', 'another string')

有效,但不可行-與我在實際項目中所做的相比,在復雜度方面,我在這里展示的內容當然被大大減少了; 我只想使用一種“直線”(非計算)正則表達式模式。 不幸的是,到目前為止,我的嘗試失敗了:

這不匹配(沒有結果),因為{2}僅應用於空格,而不應用於整個字符串:

>>> match('.*?, {2}', 'some string, another string, ')

在重復的字符串周圍添加括號,結果中包含逗號和空格

>>> match('(.*?, ){2}', 'some string, another string, ').groups()
('another string, ',)

添加另一組寄生蟲確實可以解決該問題,但是讓我感到太多:

>>> match('((.*?), ){2}', 'some string, another string, ').groups()
('another string, ', 'another string')

添加非捕獲修飾符可改善結果,但仍會遺漏第一個字符串

>>> match('(?:(.*?), ){2}', 'some string, another string, ').groups()
('another string',)

我覺得自己已經接近了,但是我似乎真的找不到合適的方法。

誰能幫我 ? 我看不到其他方法嗎?


在前幾個響應后更新:

首先,非常感謝大家,非常感謝您的幫助! :-)

就像我在原始帖子中所說的那樣,為了描述實際的核心問題,我在問題中省略了很多復雜性。 首先,在我正在研究的項目中,我正在解析大量(基於當前格式的文件)(目前為每天5萬個,目前為5種,基於行的格式大約為25個,以后可能成百上千個)。 還有XML,JSON,二進制和其他一些數據文件格式,但讓我們集中精力。

為了應付多種文件格式並利用其中許多基於行的事實,我創建了一個有點通用的Python模塊,該模塊依次加載一個文件,對每行應用一個正則表達式並返回一個大匹配的數據結構。 該模塊是一個原型,出於性能原因,生產版本將需要C ++版本,該版本將通過Boost :: Python連接,並且可能會將正則表達式的主題添加到復雜性列表中。

同樣,沒有2次重復,但是數量在當前0到70(左右)之間變化,逗號並不總是逗號,盡管我最初說的是,正則表達式模式的某些部分必須在運行時進行計算; 假設我有理由嘗試減少“動態”數量並盡可能多地使用“固定”模式。

一句話: 我必須使用正則表達式。


嘗試改寫:我認為問題的核心歸結為:是否存在Python RegEx表示法,例如涉及花括號重復並允許我捕獲

'some string, another string, '

進入

('some string', 'another string')

嗯,這可能會使范圍縮小得太遠了-但是,無論如何,這是錯誤的:-D


重新嘗試重新嘗試一下:為什么我在結果中看不到第一個字符串(“ some string”)? 為什么正則表達式會產生一個匹配項(表示某物必須有2個),而只返回1個字符串(第二個)?

即使我使用非數字重復,即使用+代替{2},問題仍然存在。

>>> match('(?:(.*?), )+', 'some string, another string, ').groups()
('another string',)

另外,返回的不是第二個字符串,而是最后一個:

>>> match('(?:(.*?), )+', 'some string, another string, third string, ').groups()
('third string',)

再次感謝您的幫助,在嘗試找出我真正想知道的內容的同時,我也從未間斷地使我對同行評審有幫助。

除非這個問題比您解釋的更多,否則我看不到使用正則表達式的意義。 使用基本的字符串方法處理起來非常簡單:

[s.strip() for s in mys.split(',') if s.strip()]

或者如果它必須是一個元組:

tuple(s.strip() for s in mys.split(',') if s.strip())

該代碼也更具可讀性。 請告訴我這是否不適用。


編輯:好的,這個問題確實比最初看起來要多。 不過,將其留作歷史用途。 (猜猜我不是“紀律” :))

如上所述,我認為此正則表達式工作正常:

import re
thepattern = re.compile("(.+?)(?:,|$)") # lazy non-empty match 
thepattern.findall("a, b, asdf, d")     # until comma or end of line
# Result:
Out[19]: ['a', ' b', ' asdf', ' d']

這里的關鍵是使用findall而不是match 問題的措詞表明您更喜歡match ,但這並不是此處工作的正確工具-它旨在為正則表達式中的每個對應組( )恰好返回一個字符串。 由於您的“字符串數”是可變的,因此正確的方法是使用findallsplit

如果這不是您所需要的,請使問題更具體。

編輯:並且,如果您必須使用元組而不是列表:

tuple(Out[19])
# Result
Out[20]: ('a', ' b', ' asdf', ' d')
import re

regex = " *((?:[^, ]| +[^, ])+) *, *((?:[^, ]| +[^, ])+) *, *"

print re.match(regex, 'some string, another string, ').groups()
# ('some string', 'another string')
print re.match(regex, ' some string, another string, ').groups()
# ('some string', 'another string')
print re.match(regex, ' some string , another string, ').groups()
# ('some string', 'another string')

沒有冒犯,但是您顯然對正則表達式有很多了解,而您最終將學到的是正則表達式無法處理此工作。 我確定這個特定的任務對正則表達式是可行的,但是那又如何呢? 您說您可能要解析數百種不同的文件格式! 您甚至提到了與正則表達式根本不兼容的JSON和XML。

幫自己一個忙:忘掉正則表達式,改為學習pyparsing 或完全跳過Python並使用獨立的解析器生成器(如ANTLR) 無論哪種情況,您都可能會發現大多數文件格式的語法均已編寫。

我認為問題的核心歸結為:是否存在Python RegEx表示法,例如涉及花括號重復,並允許我捕獲“某個字符串,另一個字符串”?

我認為沒有這樣的表示法。

但是正則表達式不僅是NOTATION的問題,也就是說,用於定義正則表達式的RE字符串。 這也是工具的問題,也就是說功能。

不幸的是,我不能使用findall,因為最初問題中的字符串只是問題的一部分,真正的字符串要長得多,所以findall僅在我執行多個正則表達式findalls / match / search時才起作用。

您應該毫不拖延地提供更多信息:我們可以更快地了解約束條件。 因為我認為,要解決已暴露的問題, findall()確實可以:

import re

for line in ('string one, string two, ',
             'some string, another string, third string, ',
             # the following two lines are only one string
             'Topaz, Turquoise, Moss Agate, Obsidian, '
             'Tigers-Eye, Tourmaline, Lapis Lazuli, '):

    print re.findall('(.+?), *',line)

結果

['string one', 'string two']
['some string', 'another string', 'third string']
['Topaz', 'Turquoise', 'Moss Agate', 'Obsidian', 'Tigers-Eye', 'Tourmaline', 'Lapis Lazuli']

現在,由於您的問題“已經省略了很多復雜性”,因此, findall()可能不足以容納這種復雜性。 然后將使用finditer(),因為它在選擇匹配項的組時提供了更大的靈活性

import re

for line in ('string one, string two, ',
             'some string, another string, third string, ',
             # the following two lines are only one string
             'Topaz, Turquoise, Moss Agate, Obsidian, '
             'Tigers-Eye, Tourmaline, Lapis Lazuli, '):

    print [ mat.group(1) for mat in re.finditer('(.+?), *',line) ]

給出相同的結果,可以通過寫其他表達式代替mat.group(1)來使其復雜化

為了總結這一點,似乎我已經通過以“動態”方式構造正則表達式模式來使用最佳解決方案:

>>> from re import match
>>> match(2 * '(.*?), ', 'some string, another string, ').groups()
('some string', 'another string')

2 * '(.*?)

這就是我所說的動態。 替代方法

>>> match('(?:(.*?), ){2}', 'some string, another string, ').groups()
('another string',)

由於以下事實而無法返回期望的結果(如Glenn和Alan所說明的那樣)

匹配時,捕獲組的每次重復都會覆蓋捕獲的內容

謝謝大家的幫助! :-)

暫無
暫無

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

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