2016-04-22 1 views
1

Я хочу использовать одно регулярное выражение + backref-выражение, которое соответствует и заменяетрегулярное выражение замены строка: опустить запятую, если backref пуст

text = 'a,b,c' с text = 'a,b,c,item_1'

text = '' с text = 'item_1' и

text = 'a' с text = 'a,item_1'.

  1. Я вообще заинтересован в растворах с использованием sed, но и с помощью python regex.

  2. В частности, я ищу решение, которое будет использоваться с модулем lineinfileAnsible (python).

Вот то, что я до сих пор (в анзибль):

regexp: "^(text[ ]*=[ ]*')([^']*)(')" 
backrefs: yes 
line:  '\1item_1,\2\3' 

Edit:, если это возможно, регулярное выражение + backref-ех пара должна игнорировать уже существующую item_1, то есть " замена»

text = 'item_1' с text = 'item_1' и

text = 'a,item_1' с text = 'a,item_1' и

text = 'a,d,x' с text = 'a,item_1,x' и т.д.

+0

А, В и С всегда отдельные буквы, или это может быть что-нибудь? –

+0

На практике элементы в списке могут быть реальными словами с символами подчеркивания, но для этого вопроса давайте останемся с одиночными символами. – Juve

ответ

1

Вы можете использовать

^(text[ ]*=[ ]*')((?:[^',]*(,?)[^']*)?[^']*)(') 

См regex и Python demo.

import re 
r = re.compile(r"^(text[ ]*=[ ]*')((?:[^',]*(,?)[^']*)?[^']*)(')") 
print(r.sub(r"\1\2\3d\4", "text = 'a,b,c'")) # => text = 'a,b,c,d' 
print(r.sub(r"\1\2\3d\4", "text = ''"))  # => text = 'd' 

То, что я сделал, это просто вставив (?:[^',]*(,?)[^']*)? подшаблона для необязательно захватить запятую. Если он присутствует внутри строки, эта запятая вставлена ​​перед d. Если это не так, запятая не вставлена.

UPDATE:

Вы можете разделить задачу на две операции:

  • Обрабатывать все случаи, когда vlaue устанавливается: использовать ^(text\[ \]*=\[ \]*')(\[^'\]+)(') и заменить \1\2,d\3
  • А затем обрабатывать с пустым значением: используйте ^(text\[ \]*=\[ \]*')(') и замените на \1d\2.

Или решение Python:

import re 
p = re.compile(r'^(text[ ]*=[ ]*\')([^\']*)(\')') 
strs = ["text = 'a,b,c'", "text = 'a'", "text = ''"] 
print([p.sub(lambda x: x.group(1) + (x.group(2) + ",d" if x.group(2) else "d") + x.group(3), s) for s in strs]) 

Смотреть на IDEONE demo

+0

Thx для этого первого ответа, я попробовал его и нашел еще один случай, который должен быть рассмотрен: замените 'text = 'a'' на' text =' a, d'' (добавлено это на вопрос) – Juve

+0

Нет способа Чтобы сделать это чисто с регулярным выражением, вам нужно оценить содержимое групп захвата. Причина в том, что вы не можете использовать шаблон условной замены в sed или python 're' regex flavors. Вас интересует код Python, который может обрабатывать этот случай? –

+0

Я разместил решение с 2 регулярными выражениями, которое может работать для вас, если у вас нет доступа к прямому коду Python. Я также разместил решение на основе Python, в котором показано, как использовать lamda для замены точно так, как вы хотите. Не уверен, что это может помочь. –

1

Это трудно сделать в sed (возможно в AWK), так как не существует замены функции обратного вызова в СЭД.

После обратного вызова подход должен работать в Python:

import re 
reg = re.compile(r"(\btext *= *)'([^']*)'") 

def repl(m): 
    if len(m.group(2)) == 0: 
     return m.group(1) + "'d'"; 
    else: 
     return m.group(1) + "'" + m.group(2) + ",d'" 


print(reg.sub(repl, r"text = 'a,b,c'")) 
print(reg.sub(repl, r"text = ''")) 
print(reg.sub(repl, r"text = 'a'")) 

Выход:

text = 'a,b,c,d' 
text = 'd' 
text = 'a,d' 

Code Demo

0

Используя негативный взгляд вокруг, я разработал working solution, даже если это не так perfect:

^(text[ ]*=[ ]*)'(((?!item_1[,]?).)*)' 

Это регулярное выражение захватывает все элементы между кавычками, если они не содержат элемент, который необходимо добавить (то есть, item_1). Backref-выражение, то просто добавляет недостающий элемент:

\1'item_1,\2' 

Однако решение не является совершенным, как он по-прежнему приводит к замыкающей запятой, если список был пуст:

text = ''   #text = 'item_1,' 
text = 'a'   #text = 'item_1,a' 
text = 'a,b,c,d'  #text = 'item_1,a,b,c,d' 

Для моего практического случая Задняя запятая не проблема. я установил его, добавив еще lineinfile задачи, используя another regex

regexp: "^(text[ ]*=[ ]*)'(.*[^,])(,?)'" 
backrefs: yes 
line:  "\\1'\\2'"