2015-10-29 68 views
3

在處理this answer的過程中,我偶然發現了一個Python重複正則表達式的異常。錨定到上次匹配結束

說我給予CSV字符串引述和無引號元素的任意數量:

21,如圖2所示,'23 .5R25 ETADT」, '描述,用逗號'

我想用'\t'替換所有',' s以外的引號。所以我想的輸出:

21 \ T2 \ t'23.5R25 ETADT '\ t'description,請用逗號'

由於將字符串中的多個匹配自然我將使用g正則表達式修飾符。我會用引號將匹配以外的字符正則表達式或引用字符串後面是','

('[^']*'|[^',]*),\s* 

我會替換爲:

\1\t 

現在的問題是正則表達式是搜索不是匹配所以它可以選擇跳過字符,直到它可以匹配。因此,而不是我想要的輸出我得到:

21 \ T2 \ t'23.5R25 ETADT '\ t'description \ twith逗號'

你可以在這裏看到此行爲的活生生的例子:https://regex101.com/r/sG9hT3/2

問:有沒有辦法將g修改過的正則表達式與上一次匹配後的字符開始匹配?


對於熟悉Perl的強大正則表達式的人,Perl提供了\G。這使我們能夠檢索匹配的最後一個位置的末尾。所以,在Perl中,我可以完成我要求與正則表達式:

\G('[^']*'|[^',]*),\s* 

這會迫使最終報告元素中的不匹配。因爲而不是讓正則表達式的實現找到一個點,正則表達式匹配\G將迫使它開始在的第一字符匹配:

「的描述,用逗號」

+0

看看[',?\ s *('[^'] *'| [^',] *)'](https://regex101.com/r/bE2aG1/1)。或者更像demo [',?[] *('[^'\ n] *'| [^',\ n] *)'](https://regex101.com/r/bE2aG1/2) 。 –

+0

@stribizhev是的這些都是可以做到的可能的解決方法。如果這就是我所能做到的,那我就很好。但我想要回答的是我們是否可以錨定這個搜索或強制匹配,而不僅僅是搜索。 –

+0

嗯,我想我明白了,如果您有任何疑問,請在我的回答下面留言。 –

回答

2

您可以使用正則表達式如下與re.search

,?\s*([^',]*(?:'[^']*'[^',]*)*) 

regex demo(我將其更改爲,?[ ]*([^',\n]*(?:'[^'\n]*'[^',\n]*)*),因爲它是一個多行演示)

在這裏,正則表達式匹配(在正則表達式的意思是單詞)...

  • ,? - 1或0逗號
  • \s* - 0或多個空白
  • ([^',]*(?:'[^']*'[^',]*)*) - 第1組存儲一個包含的捕獲文本...
    • [^',]* - 其他0個或多個字符比,'
    • (?:'[^']*'[^',]*)* - 0或更多的序列...
      • '[^']*' - 比,'其他0個或多個字符 - 不含撇號
      • [^',]*一個'string'樣子。

如果你想使用一個re.match和存儲捕獲組內捕獲的文本,因爲Python正則表達式引擎不會將所有的捕獲存儲在堆棧.NET正則表達式引擎是不可能的用CaptureCollection

此外,Python正則表達式不支持\G運算符,因此您無法在此處成功匹配的結尾處錨定任何子模式。

作爲替代方案/解決方法,您可以使用以下Python代碼返回連續的比賽,然後字符串的其餘部分

import re 

def successive_matches(pattern,text,pos=0): 
    ptrn = re.compile(pattern) 
    match = ptrn.match(text,pos) 
    while match: 
    yield match.group() 
    if match.end() == pos: 
     break 
    pos = match.end() 
    match = ptrn.match(text,pos) 
    if pos < len(text) - 1: 
    yield text[pos:] 

for matched_text in successive_matches(r"('[^']*'|[^',]*),\s*","21, 2, '23.5R25 ETADT', 'description, with a comma'"): 
    print matched_text 

IDEONE demo,輸出

21, 
2, 
'23.5R25 ETADT', 
'description, with a comma' 
+0

我的意思是即使C++可以做到這一點。你只需要找到匹配的長度,然後重新運行那個開始的正則表達式。所以即使在Python中也是如此。它只需要在正則表達式之外進行一些修改。 –

+0

請澄清你需要什麼:從'21,2',23.5R25ETADT'''描述,用逗號'只抓取3個子串:'21','2','23.5R25ETADT''? –

+0

我編輯了這個問題,但我在問題中的目標是能夠理解如何在同一行上錨定多個匹配項。 *不能*找到一個正則表達式,可以解決Python中缺少'\ G'的情況。 –