Вас смущает разница между строкой и строковым литералом.
Строковый литерал - это то, что вы помещаете между "
или '
, и интерпретатор python анализирует эту строку и помещает ее в память. Если вы пометите свой строковый литерал как необработанный строковый литерал (используя r'
), тогда интерпретатор python не изменит представление этой строки перед тем, как поместить ее в память, но после того, как они были проанализированы, они сохраняются точно так же.
Это означает, что в памяти нет такой вещи, как необработанная строка. Обе следующие строки одинаково хранятся в памяти без понятия, были ли они необработанными или нет.
r'a regex digit: \d' # a regex digit: \d
'a regex digit: \\d' # a regex digit: \d
Обе эти строки содержат \d
, и нельзя сказать, что это исходная строка. Поэтому, когда вы передаете эту строку модулю re
, он видит, что есть \d
, и видит в нем цифру, потому что модуль re
не знает, что строка пришла из необработанного строкового литерала.
В вашем конкретном примере, чтобы получить буквальную обратную косую черту, за которой следует литерал d, вы должны использовать \\d
следующим образом:
import re
text2 = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
text2_re = re.sub(r'(\\d+)/(\\d+)/(\\d+)', r'\3-\1-\2', text2)
print (text2_re) #output: Today is 11/27/2012. PyCon starts 3/13/2013.
В качестве альтернативы, без использования необработанных строк:
import re
text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
text_re = re.sub('(\\d+)/(\\d+)/(\\d+)', '\\3-\\1-\\2', text2)
print (text_re) #output: Today is 2012-11-27. PyCon starts 2013-3-13.
text2 = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
text2_re = re.sub('(\\\\d+)/(\\\\d+)/(\\\\d+)', '\\3-\\1-\\2', text2)
print (text2_re) #output: Today is 11/27/2012. PyCon starts 3/13/2013.
Я надеюсь, что это немного поможет.
Изменить: я не хотел усложнять ситуацию, но поскольку \d
не является допустимой escape-последовательностью, python не меняет ее, поэтому '\d' == r'\d'
верно. Поскольку \\
является допустимой escape-последовательностью, она изменяется на \
, поэтому вы получаете поведение '\d' == '\\d' == r'\d'
. Иногда строки сбивают с толку.
Edit2: Чтобы ответить на ваше изменение, давайте рассмотрим каждую строку отдельно:
text2_re = re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
re.sub
получает две строки (\d+)/(\d+)/(\d+)
и \3-\1-\2
. Надеюсь, теперь все пойдет так, как вы ожидаете.
text2_re1 = re.sub('(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
Опять же (поскольку \d
не является допустимым побегом строки, он не изменяется, см. Мое первое изменение) re.sub
получает две строки (\d+)/(\d+)/(\d+)
и \3-\1-\2
. Поскольку \d
не изменяется интерпретатором python r'(\d+)/(\d+)/(\d+)' == '(\d+)/(\d+)/(\d+)'
. Если вы понимаете мою первую правку, то, надеюсь, вы поймете, почему эти два случая ведут себя одинаково.
text2_re2 = re.sub(r'(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)
Этот случай немного отличается, потому что \1
, \2
и \3
- все допустимые escape-последовательности, они заменены на символ Юникода, десятичное представление которого задается числом. Это довольно сложно, но в основном сводится к следующему:
\1 # stands for the ascii start-of-heading character
\2 # stands for the ascii start-of-text character
\3 # stands for the ascii end-of-text character
Это означает, что re.sub
получает первую строку, как это было в первых двух примерах ((\d+)/(\d+)/(\d+)
), но на самом деле вторая строка равна <start-of-heading>/<start-of-text>/<end-of-text>
. Таким образом, re.sub
заменяет совпадение этой второй строкой точно, но поскольку ни один из трех (\1
, \2
или \3
) не является печатаемым символом, python вместо этого просто печатает символ-заполнитель запаса.
text2_re3 = re.sub('(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)
Это ведет себя как третий пример, потому что r'(\d+)/(\d+)/(\d+)' == '(\d+)/(\d+)/(\d+)'
, как объяснено во втором примере.
person
Sean1708
schedule
11.05.2015