2016-12-09 6 views
3

Я встречаюсь с запутанными и, казалось бы, противоречивыми правилами относительно сырых строк. Рассмотрим следующий пример:Raw Strings, Python и re, Normal vs Special Characters

 
>>> text = 'm\n' 
>>> match = re.search('m\n', text) 
>>> print match.group() 
m 

>>> print text 
m 

Это работает, и это нормально.

 
>>> text = 'm\n' 
>>> match = re.search(r'm\n', text) 
>>> print match.group() 
m 

>>> print text 
m 

Снова это работает. Но разве это не должно вызывать ошибку, потому что необработанная строка содержит символы m\n, а фактический текст содержит новую строку?

>>> text = r'm\n' 
>>> match = re.search(r'm\n', text) 
>>> print match.group() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'NoneType' object has no attribute 'group' 
>>> print text 
m\n 

Вышеприведенное выше, вызывает ошибку, хотя обе являются исходными строками. Это означает, что оба содержат только текст m\n без новых строк.

>>> text = r'm\n' 
>>> match = re.search(r'm\\n', text) 
>>> print text 
m\n 
>>> print match.group() 
m\n 

Вышеупомянутые работы, на удивление. Почему мне приходится скрывать обратную косую черту в re.search, но не в самом тексте?

Тогда есть обратный слэш с нормальными символами, которые не имеют никакого особого поведения:

>>> text = 'm\&' 
>>> match = re.search('m\&', text) 
>>> print text 
m\& 
>>> print match.group() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'NoneType' object has no attribute 'group' 

Это не соответствует, хотя и шаблону, и строка не имеют специальные символы.

В этой ситуации никакая комбинация сырых строк не работает (текст как необработанная строка, паттерны как необработанная строка, обе или ни одна).

Однако рассмотрим последний пример. Выход из текстовой переменной, 'm\\&', не работает, но экранирование в шаблоне делает. Это соответствует поведение выше - даже незнакомым, я чувствую, учитывая, что \& не представляет особого смысла либо Python или Re:

>>> text = 'm\&' 
>>> match = re.search(r'm\\&', text) 
>>> print text 
m\& 
>>> print match.group() 
m\& 

Мое понимание исходных строк в том, что они подавляют поведение обратной косой черты в питона , Для регулярных выражений это важно, поскольку позволяет re.search применять свое внутреннее поведение обратной косой черты и предотвращать конфликты с Python. Однако в ситуациях, подобных выше, где обратная косая черта фактически ничего не значит, я не уверен, почему это кажется необходимым. Хуже того, я не понимаю, почему мне нужно обратное слэш для шаблона, но не текст, и когда я делаю как необработанную строку, это, похоже, не работает.

The docs не дают большого руководства в этом отношении. Они сосредоточены на примерах с очевидными проблемами, такими как '\section', где \s является метасимволом. Ищете полный ответ, чтобы предотвратить непредвиденное поведение, такое как это.

+0

Нечего удивляться. 'r'm \ n' имеет длину 3 (' m', '' '' ',' n'). Регулярное выражение 'r'm \ n'' соответствует 2 строкам символов,' m' + newline. –

+0

Это делает ваш вопрос обманом http://stackoverflow.com/questions/22937618/reference-what-does-this-regex-mean. «R» \ n'' - это шаблон соответствия LF. –

ответ

0
text = r'm\n' 
match = re.search(r'm\\n', text) 

Первая линия с помощью r остановок Python интерпретировать \n, как один байт.

Вторая линия с использованием r играет ту же роль, как first.Using \ предотвращает регулярное выражение от интерпретации, как \n .Regex также использует \ как \s, \d.

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

\ обратной косой черты экранирующего символа. Обратная косая черта придает особое значение персонажу, следующему за ним. Например, комбинация «\ n» обозначает новую строку, один из управляющих символов. Комбинация «\ w» означает символ «слово», одна из удобных escape-последовательностей, в то время как «\ 1» является одним из специальных символов замены. Пример: регулярное выражение «aa \ n» пытается совместить два последовательных символа «a» в конце строки, включая сам символ новой строки. Пример: «a +» соответствует «a +», а не серию из одного или «a».

+0

@GHH '\\' is en escape character.Is вы хотите совместить это с необходимостью использовать '\\\'. Вы не можете определить строку 'a \\' в python – vks

+0

Спасибо, я вижу путаницу: '\ n 'также имеет особое значение в regex. Но возьмите следующую ситуацию: текст и шаблон = 'r'm \ k''. Это также вызывает ошибку. Что относительно ситуаций, когда 'r \ [whatever]' определенно ** не является особенным ни в Python, ни в re? Почему мне все еще нужно избегать обратной косой черты? – GHH

+0

@GHH, потому что '\\' сам является специальным символом, и если ур использует его в буквальном смысле, вам нужно избегать его для интерпретатора regex, а не python. – vks

0

Для того, чтобы понять внутреннее представление строк, которые вы смущаете. Я бы рекомендовал вам использовать функции repr и len встроенных функций. Используя те, вы сможете точно понять, как работают строки, и вы больше не будете путать насчет соответствия шаблонов, потому что вы точно узнаете внутреннее представление. Например, предположим, что вы хотите анализируем строки у вас возникли проблемы с:

use_cases = [ 
    'm\n', 
    r'm\n', 
    'm\\n', 
    r'm\\n', 
    'm\&', 
    r'm\&', 
    'm\\&', 
    r'm\\&', 
] 

for u in use_cases: 
    print('-' * 10) 
    print(u, repr(u), len(u)) 

Выход будет:

---------- 
m 
'm\n' 2 
---------- 
m\n 'm\\n' 3 
---------- 
m\n 'm\\n' 3 
---------- 
m\\n 'm\\\\n' 4 
---------- 
m\& 'm\\&' 3 
---------- 
m\& 'm\\&' 3 
---------- 
m\& 'm\\&' 3 
---------- 
m\\& 'm\\\\&' 4 

Таким образом, вы можете видеть именно различия между нормальными/необработанных строк.

+0

Прохладный трюк. Я определенно буду использовать это. Благодарю. – GHH

1

В обычных строках Python, 'm\n', то \n представляет один символ новой строки, в то время как в сыре строки r'm\n'\ и n только сам. Пока что так просто.

Если передать строку 'm\n' как образец re.search(), вы передаете строку два-символа (m с последующим переводом строки), и re будет счастливо пойти и найти экземпляры этой строки из двух символов для вас.

Если передать строку трехсимвольной r'm\n', модуль самого re будет интерпретировать два символа \n как имеющие особое значение «совпадает с символом новой строки», так что вся картина означает «совпадать с m с последующим по новой строке ", как и раньше.

В вашем третьем примере, так как строка r'm\n' не содержит символ новой строки, нет никакого матча:

>>> text = r'm\n' 
>>> match = re.search(r'm\n', text) 
>>> print(match) 
None 

С рисунком r'm\\n', вы передаете два фактических обратные слэши re.search(), и снова, сам модуль re интерпретирует двойную обратную косую черту как «совпадение с одним символом обратной косой черты».

В случае 'm\&' происходит нечто иное. Python обрабатывает обратную косую черту как обычный символ, потому что он не является частью escape-последовательности. re, с другой стороны, просто отбрасывает \, поэтому шаблон эффективен m&.Вы можете видеть, что это верно, тестируя образец против 'm&':

>>> re.search('m\&', 'm&').group() 
'm&' 

Как и прежде, удваивая обратной косой черты рассказывает re для поиска актуальной обратной косой черты:

>>> re.search(r'm\\&', 'm\&').group() 
'm\\&' 

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

>>> print(re.search(r'm\\&', 'm\&').group()) 
m\& 
+0

Спасибо за это! Теперь я понимаю, что в Python обратная косая черта ведет себя только как особый символ, когда она находится перед определенными символами.Вот почему 'pattern = r'm \\ & '' соответствует как 'text = r'm \ &'', так и 'text = r'm \\ & ''. Однако в регулярном выражении обратная косая черта всегда является специальным символом, независимо от того, изменит ли он поведение следующего символа (например, '\ w') или нет (например,' \ & '). Поэтому, если я хочу просто нормальное backspace, я всегда должен убегать в регулярном выражении, хотя в обычном Python это иногда необязательно. – GHH

0

Чтобы объяснить это простыми словами, \<character> имеет особое значение в регулярных выражениях. Например \s для пробельных символов, \d для десятичных цифр, \n для символов новой строки, и т.д.

При определении строки в

s = 'foo\n' 

Эта строка содержит символы f, o, o и символ новой строки (длина 4).

Тем не менее, при определении сырой строки:

s = r'foo\n' 

Эта строка содержит символы f, o, o, \ и n (длина 5).

Когда вы скомпилируете регулярное выражение с необработанным \n (т. Е. r'\n'), оно будет соответствовать всем новым строкам. Аналогично, просто используя символ новой строки (т. Е. '\n'), он будет соответствовать символам новой строки, как и a соответствует a и так далее.

Как только вы поймете эту концепцию, вы сможете выяснить остальное.

Чтобы уточнить немного дальше. Чтобы соответствовать символу обратной косой черты \ с использованием regex, действительное регулярное выражение равно \\, которое в Python будет r'\\' или его эквивалент '\\\\'.