Использовать пользовательскую функцию замены :
re.sub(pattern, repl, string, count=0, flags=0)
...
Если repl
- функция, она вызывается для каждого не перекрывающееся вхождение pattern
.
Функция repl
вызывается для каждого вхождения одного ;
и для выражений в скобках. Поскольку re.sub
не находит перекрывающихся последовательностей, самая первая открывающая скобка будет запускать полное совпадение вплоть до последней закрывающей скобки.
import re
def repl(m):
contents = m.group(1)
if '(' in contents:
return contents
return ';\n'
str1 = 'for (j=0; j<len; j++) a = (s) + (4); test = 5;'
str2 = 'for (j=0; j<(len); (j++)) a = (s) + (4); test = 5;'
print (re.sub (r'(;\s*|\(.*\))', repl, str1))
print (re.sub (r'(;\s*|\(.*\))', repl, str2))
Результат:
for (j=0; j<len; j++) a = (s) + (4);
test = 5;
for (j=0; j<(len); (j++)) a = (s) + (4);
test = 5;
Миссия выполнена, для ваших (очень маленьких) выборочных данных.
Но подождите!
Небольшое, но действительное изменение в одном из примеры
str1 = 'for (j=0; j<len; j++) test = 5; a = (s) + (4);'
ломает это с неправильным выводом:
for (j=0; j<len; j++) test = 5; a = (s) + (4);
Обойти это невозможно, вам нужен конечный автомат вместо:
def state_match (text):
parentheses = 0
drop_space = False
result = ''
for character in text:
if character == '(':
parentheses += 1
result += '('
elif character == ')':
parentheses -= 1
result += ')'
elif character == ' ':
if not drop_space:
result += ' '
drop_space = False
elif character == ';':
if parentheses:
result += character
else:
result += ';\n'
drop_space = True
else:
result += character
return result
str1 = 'for (j=0; j<len; j++) a = (s) + (4); test = 5;'
str2 = 'for (j=0; j<(len); (j++)) a = (s) + (4); test = 5;'
str3 = 'for (j=0; j<len; j++) test = 5; a = (s) + (4);'
print (state_match(str1))
print (state_match(str2))
print (state_match(str3))
дает правильные результаты:
for (j=0; j<len; j++) a = (s) + (4);
test = 5;
for (j=0; j<(len); (j++)) a = (s) + (4);
test = 5;
for (j=0; j<len; j++) test = 5;
a = (s) + (4);