2012-06-15 2 views
1

Я хотел бы искать и заменять все вхождения вне <>. Я могу предположить, что все скобки согласованы. Например, я хочу заменить 'BLOCK' с '*':Peyt regex множественные вхождения вне скобок

BLOCKaaa<BLOCKaaaa>aaaaa<>BLOCKzzzBLOCKBLOCK 

станет:

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

Я попытался следующие:

-Добавить> в начале и < в конце линии, назовем его LINEwith> <

-Run:

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

Но это дает мне это вместо:

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

Я не уверен, как заменить все вхождения между> <

Может кто-нибудь помочь мне с этим? Или предложите лучший способ сделать это.

Thank you.

+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) 

(это, очевидно, не работает, если есть какая-либо непарные скобки.)