Python中的原始字符串和正则表达式

flu*_*y03 6 python regex escaping backslash rawstring

我在以下代码中对原始字符串有一些困惑:

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 2012-11-27. PyCon starts 2013-3-13.

print (r'(\d+)/(\d+)/(\d+)') #output: (\d+)/(\d+)/(\d+)
Run Code Online (Sandbox Code Playgroud)

正如我理解原始字符串,没有r,\被视为转义字符; 使用r,反斜杠\被视为字体.

但是,我在上面的代码中无法理解的是:在正则表达式第5行中,即使有一个r,里面的" \ d "被视为一个数字[0-9]而不是一个反斜杠\加一个信d.

在第二个打印行8中,所有字符都被视为原始字符串.

有什么不同?

附加版:

我做了以下四种变化,有或没有r:

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)
text2_re1 = re.sub('(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
text2_re2 = re.sub(r'(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)
text2_re3 = re.sub('(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)

print (text2_re)
print (text2_re1)
print (text2_re2)
print (text2_re3)
Run Code Online (Sandbox Code Playgroud)

并获得以下输出:

你能具体解释这四种情况吗?

Sea*_*708 7

你对字符串和字符串文字之间的区别感到困惑.

字符串文字就是你放在之间的东西,"或者'python解释器解析这个字符串并将它放入内存中.如果将字符串文字标记为原始字符串文字(使用r'),那么python解释器在将其放入内存之前不会更改该字符串的表示形式,但一旦解析它们,它们的存储方式完全相同.

这意味着在内存中没有原始字符串这样的东西.以下字符串都以相同的方式存储在内存中,没有关于它们是否是原始的概念.

r'a regex digit: \d'  # a regex digit: \d
'a regex digit: \\d'  # a regex digit: \d
Run Code Online (Sandbox Code Playgroud)

这两个字符串都包含\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.
Run Code Online (Sandbox Code Playgroud)

或者,不使用原始字符串:

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.
Run Code Online (Sandbox Code Playgroud)

我希望有所帮助.

编辑:我不想让事情复杂化,但因为\d不是一个有效的转义序列python不会改变它,所以'\d' == r'\d'是真的.因为它\\ 一个有效的转义序列\,所以它会被改变为,所以你得到了这个行为'\d' == '\\d' == r'\d'.字符串有时会让人感到困惑.

编辑2 :要回答您的编辑,让我们具体看一下每一行:

text2_re = re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
Run Code Online (Sandbox Code Playgroud)

re.sub收到两个字符串(\d+)/(\d+)/(\d+)\3-\1-\2.希望这表现得像你现在所期望的那样.

text2_re1 = re.sub('(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
Run Code Online (Sandbox Code Playgroud)

再次(因为\d它不是一个有效的字符串转义,它不会被更改,请参阅我的第一个编辑)re.sub收到两个字符串(\d+)/(\d+)/(\d+)\3-\1-\2.因为\dpython解释器不会改变它r'(\d+)/(\d+)/(\d+)' == '(\d+)/(\d+)/(\d+)'.如果您理解我的第一次编辑,那么希望您应该理解为什么这两种情况的行为相同.

text2_re2 = re.sub(r'(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)
Run Code Online (Sandbox Code Playgroud)

这种情况是因为有一点不同\1,\2并且\3都是有效的转义序列,它们与替换Unicode字符,其十进制表示是由数给出.这很复杂但它基本上归结为:

\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
Run Code Online (Sandbox Code Playgroud)

这意味着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)
Run Code Online (Sandbox Code Playgroud)

这与第三个示例相似,因为r'(\d+)/(\d+)/(\d+)' == '(\d+)/(\d+)/(\d+)'如第二个示例中所述.


Jer*_*rry 6

你必须区分 python 解释器和re模块。

在 python 中,如果字符串不是原始字符串,则反斜杠后跟一个字符可能表示特殊字符。例如,\n将表示换行符,\r将表示回车符,\t将表示制表符,\b表示非破坏性退格键。就其本身而言,\d在 python 字符串中并不意味着任何特殊的东西。

然而,在正则表达式中,有一堆字符在 Python 中并不总是意味着任何意义。但这就是问题所在,“并不总是”。可能被误解的一件事是,\b在 python 中是退格键,在正则表达式中意味着单词边界。这意味着,如果您将未加工的值传递\b给正则表达式的正则表达式部分,则在传递给正则表达式函数之前\b,它会被退格键替换,并且在那里没有任何意义。因此,您必须绝对通过其反斜杠来传递,为此,您要么转义反斜杠,要么原始字符串。b

回到你关于\d,\d在 python 中没有任何特殊含义的问题,所以它保持不变。作为正则\d表达式传递的内容由正则表达式引擎转换,该引擎是 python 解释器的独立实体。


每个问题的编辑:

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)
text2_re1 = re.sub('(\d+)/(\d+)/(\d+)', r'\3-\1-\2', text2)
text2_re2 = re.sub(r'(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)
text2_re3 = re.sub('(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2)

print(text2_re)
print(text2_re1)
print(text2_re2)
print(text2_re3)
Run Code Online (Sandbox Code Playgroud)

前两个应该很简单。re.sub通过匹配数字和正斜杠并用连字符以不同的顺序替换它们来完成其工作。由于\d在Python中没有任何特殊含义,\d因此传递给re.sub表达式是否是原始的。

发生第三和第四种情况是因为您尚未为替换表达式生成字符串。\1,在Python中\2\3特殊的含义,分别代表白色(或未填充)笑脸、黑色(填充)笑脸和心形(如果无法显示字符,则会得到这些“字符框”)。因此,您不是用捕获的组进行替换,而是用特定字符替换字符串。

在此输入图像描述