Регулярний вираз Python - префікс r


87

Хтось може пояснити, чому працює приклад 1 нижче, коли rпрефікс не використовується? Я думав, що rпрефікс повинен використовуватися щоразу, коли використовуються екрануючі послідовності. Приклад 2 і приклад 3 демонструють це.

# example 1
import re
print (re.sub('\s+', ' ', 'hello     there      there'))
# prints 'hello there there' - not expected as r prefix is not used

# example 2
import re
print (re.sub(r'(\b\w+)(\s+\1\b)+', r'\1', 'hello     there      there'))
# prints 'hello     there' - as expected as r prefix is used

# example 3
import re
print (re.sub('(\b\w+)(\s+\1\b)+', '\1', 'hello     there      there'))
# prints 'hello     there      there' - as expected as r prefix is not used

Відповіді:


86

Оскільки \розпочинати екранні послідовності слід лише тоді, коли вони є дійсними послідовностями екранування.

>>> '\n'
'\n'
>>> r'\n'
'\\n'
>>> print '\n'


>>> print r'\n'
\n
>>> '\s'
'\\s'
>>> r'\s'
'\\s'
>>> print '\s'
\s
>>> print r'\s'
\s

Якщо немає префікса 'r' або 'R', послідовності екранування в рядках інтерпретуються відповідно до правил, подібних до тих, що використовуються стандартом C. Розпізнаними послідовностями екранування є:

Escape Sequence   Meaning Notes
\newline  Ignored  
\\    Backslash (\)    
\'    Single quote (')     
\"    Double quote (")     
\a    ASCII Bell (BEL)     
\b    ASCII Backspace (BS)     
\f    ASCII Formfeed (FF)  
\n    ASCII Linefeed (LF)  
\N{name}  Character named name in the Unicode database (Unicode only)  
\r    ASCII Carriage Return (CR)   
\t    ASCII Horizontal Tab (TAB)   
\uxxxx    Character with 16-bit hex value xxxx (Unicode only) 
\Uxxxxxxxx    Character with 32-bit hex value xxxxxxxx (Unicode only) 
\v    ASCII Vertical Tab (VT)  
\ooo  Character with octal value ooo
\xhh  Character with hex value hh

Ніколи не покладайтесь на необроблені рядки для літералів шляху, оскільки необроблені рядки мають досить своєрідну внутрішню роботу, яка, як відомо, покусала людей у ​​дупу:

Коли присутній префікс "r" або "R", символ, що стоїть за зворотною рискою рискою, включається в рядок без змін, а всі зворотні скісні риски залишаються в рядку. Наприклад, рядковий літерал r"\n"складається з двох символів: зворотної косої риски та малої літери "n". Рядкові лапки можна уникнути зворотною рискою рискою, але зворотна риска залишається в рядку; наприклад, r"\""є дійсним рядковим літералом, що складається з двох символів: зворотної косої риски та подвійної лапки; r"\"не є дійсним літеральним рядком (навіть необроблений рядок не може закінчуватися непарною кількістю зворотних скісних рисок). Зокрема, необроблений рядок не може закінчуватися однією зворотною косою рисою (оскільки зворотна коса риса буде уникати наступного символу лапки). Зауважте також, що одинарна коса коса риска, після якої йде новий рядок, інтерпретується як ці два символи як частина рядка,

Щоб краще проілюструвати цей останній пункт:

>>> r'\'
SyntaxError: EOL while scanning string literal
>>> r'\''
"\\'"
>>> '\'
SyntaxError: EOL while scanning string literal
>>> '\''
"'"
>>> 
>>> r'\\'
'\\\\'
>>> '\\'
'\\'
>>> print r'\\'
\\
>>> print r'\'
SyntaxError: EOL while scanning string literal
>>> print '\\'
\

Як незначне виправлення '\s'(подібне r'\s') також представляється як '\\s', через те, що '\s'не є розпізнаною послідовністю виходу.
Massood Khaari

@MassoodKhaari Я б поклявся, що результат був правильним, коли я писав цю відповідь ... Виправлено.
Естебан Кюбер

1
8 років, безумовно, виправдовують магічну зміну поведінки пітона. : D
Massood Khaari

34

'r' означає, що наступне є "необробленим рядком", тобто. символи зворотної косої риски трактуються буквально, а не означають особливе ставлення до наступного символу.

http://docs.python.org/reference/lexical_analysis.html#literals

так '\n'само є один новий рядок
і r'\n'складається з двох символів - зворотна коса риса і буква 'n'
іншим способом її написання було б '\\n'тому, що перша зворотна коса риса витікає з другої

еквівалентний спосіб написання цього

print (re.sub(r'(\b\w+)(\s+\1\b)+', r'\1', 'hello     there      there'))

є

print (re.sub('(\\b\\w+)(\\s+\\1\\b)+', '\\1', 'hello     there      there'))

Через те, як Python обробляє символи, які не є дійсними символами екранування, необхідні не всі з цих подвійних зворотних скісних рисок - наприклад, '\s'=='\\s'те ж саме не стосується '\b'і '\\b'. Я віддаю перевагу чіткому і подвоювати всі зворотні скісні риски.


5

Не всі послідовності, що включають зворотні скісні риски, є послідовностями екранування. \tі \fє, наприклад, але \sне є. У несирому рядковому літералі будь- \який, який не є частиною екрануючої послідовності, розглядається як просто інший \:

>>> "\s"
'\\s'
>>> "\t"
'\t'

\b є послідовністю екранування, проте приклад 3 не вдається. (І так, деякі люди вважають таку поведінку досить прикрою).


Точно так. Хоча, @JT, я рекомендую використовувати '\\ s' або r '\ s', інакше ти ненавмисно випадково вдаришся до деяких послідовностей екранування, які ти не мав на увазі.
Blair Conrad

Дійсно: завжди використовуйте необроблені рядкові літерали, коли ви хочете, щоб рядок містив зворотні скісні риски (на відміну від того, щоб насправді хотіти втеча послідовностей.)
Thomas Wouters

@Thomas: rвсе одно уникає деяких послідовностей, коли вони з'являються в кінці рядка: r"\"недійсний, для цього вам потрібно зробити "\\". Якщо ви це зробите r"\\", ви отримаєте \\ надрукований ( "\\\\"рядок). Будьте обережні з цим.
Естебан Кюбер

Так, необроблені рядкові літерали не можуть закінчуватися одним символом `\`.
Thomas Wouters

@ Блер / Томас: дякую - це загальне правило, якого я дотримувався, спочатку збентежило мене! ... все зрозуміло зараз, дякую усім. Хоча, дотримуючись цього правила ... під час читання шаблону з простого текстового файлу, як би шаблон передавався як необроблений літеральний рядок?
JT.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.