2012-06-15 100 views
1

我想搜索並替換<>之外的所有出現。 我可以假設所有的括號是匹配的。 例如,我想用 '*' 來代替 'BLOCK':Python正則表達式出現在括號外多個出現

BLOCKaaa<BLOCKaaaa>aaaaa<>BLOCKzzzBLOCKBLOCK 

將成爲:

*aa<BLOCKaaaa>aaaaa<>*zzz** 

我曾嘗試以下:

- 添加>開頭和<在行尾,稱之爲LINEwith> <

- 運行:

re.sub('(>[^<>]*)(BLOCK)+? ([^<>]*<?)', '\\1*\\3', LINEwith><) 

但它給了我這個:

'>*aaa<BLOCKaaaa>aaaaa<>BLOCKzzzBLOCK*<' 

我不知道如何更換之間所有出現> <

有人可以幫助我?或者提出一個更好的方法。

謝謝。

+2

可以''<' and '>發生拼圖?那麼'aaaaa aaa> aaaa'或者只能像你在你的例子中描述的那樣? –

+0

我還沒有遇到過,但我不會說我可以排除。 –

回答

4

由於您可以認爲括號總是匹配,所以以下內容應該可以工作。

re.sub(r'BLOCK(?=[^>]*(<|$))', '*', line) 

這也假定不能有嵌套括號。

它使用一個前瞻,以確保有下一個<字符或字符串結束前沒有>字符。由於正在使用lookahead,正則表達式實際上匹配的唯一文本是BLOCK,所以替換簡化爲'*',因爲不再有任何捕獲組。

這裏是一個版本,將工作到嵌套括號一層:

BLOCK(?=([^<>]*(<(<[^>]*>|[^<>])*>)?)*$) 

例子:

>>> p = re.compile(r'BLOCK(?=([^<>]*(<(<[^>]*>|[^<>])*>)?)*$)') 
>>> p.sub('*', 'BLOCK<BLOCK<BLOCK>>BLOCK<BLOCK>BLOCKzzzBLOCKBLOCK') 
'*<BLOCK<BLOCK>>*<BLOCK>*zzz**' 

正如你所看到的,正則表達式是不是真的適合於嵌套數據結構。

+0

非常感謝。如果有嵌套括號,我想限制搜索最外層以外的內容? –

+1

@QNguyen編輯了一個嵌套級別的版本,它很快變得醜陋! –

+0

用正則表達式分析任意嵌套的結構是不可能的。如果您需要任意嵌套,請參閱pyparsing等內容。 – BrenBarn

0

如果括號是嵌套的,則不能使用正則表達式。怎麼樣split -fu?

def replace_outside(string, original, replacement): 
    level = 0 #the level of nesting - 0 is outside 
    result = [] #a temp list holding the result 
    while string: 
     #split the string until the first '<', save everything before that in 
     #current and process the rest in the next iteration 
     splitstr = string.split("<", 1) 
     if len(splitstr) == 1: current, string = string, "" 
     else: current, string = tuple(splitstr) 
     if level == 0: 
      #we're outside - replace everything in current string 
      current = current.replace(original, replacement) 
     else: 
      #decrease the level by the number of closing brackets in current 
      level -= current.count(">") 
      if level == 0: 
       #everything after the last '>' is outside 
       inner, outer = current.rsplit(">", 1) 
       #replace outer and join with inner again 
       outer = outer.replace(original, replacement) 
       current = '>'.join([inner, outer]) 
     #append the string to the result list and increase level by one 
     result.append(current) 
     level += 1 
    #return the result list joined by the '>' we split it by 
    return '<'.join(result) 

(如果有任何不匹配的括號這顯然會失敗。)