2016-11-18 2 views
2

Есть строки из ввода пользователя, которые мне нужно преобразовать. Вариант использования довольно прост:Обращение с escape-символами в строке

  • Когда точка с запятой находится в строке, строка разделяется на несколько строк.
  • Когда есть две точки с запятой в строке, они преобразуются в одну.

В теории нет большой проблемы. Я использую Python, но я уверен, что другие с другими языками найдут это легко с регулярными выражениями.

import re 

def get_lines(text): 
    """Return a list of lines (list of str).""" 
    command_stacking = ";" 
    delimiter = re.escape(command_stacking) 
    re_del = re.compile("(?<!{s}){s}(?!{s})".format(s=delimiter), re.UNICODE) 
    chunks = re_del.split(text) 

    # Clean the double delimiters 
    for i, chunk in enumerate(chunks): 
     chunks[i] = chunk.replace(2 * command_stacking, command_stacking) 

    return chunks 

Это похоже на работу:

>>> get_lines("first line;second line;third line with;;a semicolon") 
['first line', 'second line', 'third line with;a semicolon'] 
>>> 

Но когда есть три или четыре точки с запятой, он не ведет себя так, как ожидалось.

Множественная запятая игнорируется регулярным выражением (как они должны), но при замене ;; на ;, ;;; заменяются ;;, ;;;; заменяется ;;... и так далее. Было бы здорово, если бы 2 был заменен на 1, 3 на 2, 4 на 3 ... это то, что я мог бы объяснить своим пользователям.

Что было бы лучшим решением для этого?

Спасибо за вашу помощь,

ответ

1

РЕПЛ аргумент re.sub может быть функцией.

>>> s = 'a;;b;;;c;;;;d' 
>>> pattern = ';{2,}' 
>>> def f(m): 
    return m.group(0)[1:] 

>>> re.sub(pattern, f, s) 
'a;b;;c;;;d' 
>>> 
1

Вместо использования re.sub() строки replace метода с count=1

import re 
re.sub(';;', ';', 'foo;;;bar', count=1) 

https://docs.python.org/2/library/re.html#re.sub

+0

выглядит как лучшее решение, даже если я не уверен, что он будет работать.Кажется, он заменяет две точки с запятой на одну, три на две, четыре на три, пять на четыре и так далее. –

+0

Аргумент 'count = 1' указывает, что он заменяет только один экземпляр двойной точки с запятой. – Batman

0

Вы можете использовать re.split с просмотровым обходными.

Пример

>>> re.split(r'(?<!;);(?!;)', string) 
['first line', 'second line', 'third line with;;a semicolon'] 

Regex

  • (?<!;) Отрицательный взгляд позади. Проверяет, является ли ; не предшествует другой ;
    • ; сопоставляет Отрицательный взгляд ;
  • (?!;) вперед. Проверки, если ; не следует другой ;

>>> [x.replace(';;', ';') for x in re.split(r'(?<!;);(?!;)', string)] 
['first line', 'second line', 'third line with;a semicolon']