Регулярные выражения 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, не стесняйтесь публиковать его, и я также соглашусь с ним в качестве ответа.