Регулярные выражения Python для реализации строкового unescaping
Я пытаюсь реализовать строковое unescaping с регулярным выражением Python и обратными ссылками, и, похоже, он не очень хорошо работает. Я уверен, что это то, что я делаю неправильно, но я не могу понять, что...
>>> import re
>>> mystring = r"This is \n a test \r"
>>> p = re.compile( "\\\\(\\S)" )
>>> p.sub( "\\1", mystring )
'This is n a test r'
>>> p.sub( "\\\\\\1", mystring )
'This is \\n a test \\r'
>>> p.sub( "\\\\1", mystring )
'This is \\1 a test \\1'
Я хотел бы заменить \\[ char] на\[char], но обратные ссылки в Python, похоже, не соответствуют тем же правилам, которые они выполняют в любой другой реализации, которую я когда-либо использовал. Может кто-то пролил свет?
Ответы
Ответ 1
Разве это не то, что делает второй пример Андерса?
В 2.5 есть также кодировка string-escape
, которую вы можете применить:
>>> mystring = r"This is \n a test \r"
>>> mystring.decode('string-escape')
'This is \n a test \r'
>>> print mystring.decode('string-escape')
This is
a test
>>>
Ответ 2
Хорошо, я думаю, что вы, возможно, пропустили r или не допустили обратную косую черту...
"\\n" == r"\n"
>>> import re
>>> mystring = r"This is \\n a test \\r"
>>> p = re.compile( r"[\\][\\](.)" )
>>> print p.sub( r"\\\1", mystring )
This is \n a test \r
>>>
Что, если я понял, это то, что было запрошено.
Я подозреваю, что более распространенный запрос таков:
>>> d = {'n':'\n', 'r':'\r', 'f':'\f'}
>>> p = re.compile(r"[\\]([nrfv])")
>>> print p.sub(lambda mo: d[mo.group(1)], mystring)
This is \
a test \
>>>
Заинтересованный студент также должен прочитать Ken Thompson "Размышления о доверительном доверии" , в котором наш герой использует подобный пример, чтобы объяснить опасения доверия компиляторы, которые вы сами не загрузили из машинного кода.
Ответ 3
Вы обманываете представление Python строки результата. Выражение Python:
'This is \\n a test \\r'
представляет строку
This is \n a test \r
что я думаю, что вы хотели. Попробуйте добавить "печать" перед каждым вызовом p.sub(), чтобы напечатать фактическую строку, возвращаемую вместо представления строки Python.
>>> mystring = r"This is \n a test \r"
>>> mystring
'This is \\n a test \\r'
>>> print mystring
This is \n a test \r
Ответ 4
Идея заключается в том, что я буду читать в экранированной строке и отменить ее (особенно не хватает Python, для которой вам не нужно прибегать к регулярным выражениям в первую очередь). К сожалению, меня не обманывают обратные косые черты...
Другой иллюстративный пример:
>>> mystring = r"This is \n ridiculous"
>>> print mystring
This is \n ridiculous
>>> p = re.compile( r"\\(\S)" )
>>> print p.sub( 'bloody', mystring )
This is bloody ridiculous
>>> print p.sub( r'\1', mystring )
This is n ridiculous
>>> print p.sub( r'\\1', mystring )
This is \1 ridiculous
>>> print p.sub( r'\\\1', mystring )
This is \n ridiculous
Что бы я хотел напечатать,
This is
ridiculous
Ответ 5
Марк; его второй пример требует, чтобы каждый экранированный символ сначала попадал в массив, который генерирует KeyError, если escape-последовательность не входит в массив. Он умрет на чем угодно, кроме трех предоставленных символов (дайте\v a try), и перечисление каждой возможной escape-последовательности каждый раз, когда вы захотите отменить строку (или сохранить глобальный массив), является действительно плохим решением. Аналогично PHP, используя preg_replace_callback()
с лямбдой вместо preg_replace()
, что совершенно не нужно в этой ситуации.
Извините, если я одержусь как член, я просто разочарован Python. Это поддерживается всеми другими механизмами регулярных выражений, которые я когда-либо использовал, и я не понимаю, почему это не сработает.
Спасибо, что ответили; функция string.decode('string-escape')
- это именно то, что я искал изначально. Если у кого-то есть общее решение проблемы с regex backreference, не стесняйтесь публиковать его, и я также соглашусь с ним в качестве ответа.