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

时间:2015-05-11 09:30:18

标签: 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+)

根据我对原始字符串的理解,如果没有 r \ 将被视为转义字符;使用 r ,反斜杠 \ 将被视为字体。

但是,我在上面的代码中无法理解的是: 在正则表达式第5行中,即使存在 r ," \ d " inside被视为一个数字[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)

获得以下输出:

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

4 个答案:

答案 0 :(得分:7)

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

字符串文字是放在"'之间的内容,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不是有效的转义序列,python不会改变它,所以'\d' == r'\d'为真。由于\\ 有效的转义序列,因此它会更改为\,因此您会获得行为'\d' == '\\d' == r'\d'。字符串有时会让人感到困惑。

编辑2 :要回答您的修改,请详细查看每一行:

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+)和{{1} }。由于\3-\1-\2没有被python解释器\d更改。如果您理解我的第一次编辑,那么希望您应该理解为什么这两种情况的行为相同。

r'(\d+)/(\d+)/(\d+)' == '(\d+)/(\d+)/(\d+)'

这种情况略有不同,因为text2_re2 = re.sub(r'(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2) \1\2都是有效的转义序列,它们被unicode character替换,其小数表示由数。这很复杂但它基本上归结为:

\3

这意味着\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)都不是可打印字符,因此python只打印一个库存占位符而不是角色。

\3

这与第三个示例的行为类似于text2_re3 = re.sub('(\d+)/(\d+)/(\d+)', '\3-\1-\2', text2) ,如第二个示例中所述。

答案 1 :(得分:2)

你必须在python解释器和re模块之间做出区分。

在python中,如果字符串未生成,则后跟字符的反斜杠可能表示特殊字符。例如,\n表示换行符,\r表示回车符,\t表示制表符,\b表示非破坏性退格。就其本身而言,python字符串中的\d并不意味着什么特别的。

然而,在正则表达式中,有许多字符在python中并不总是意味着什么。但这就是问题所在,而且并非总是如此。其中一个可以被误解的是\b,它在python中是一个退格,在正则表达式中意味着一个单词边界。这意味着,如果您将未绘制的\b传递给正则表达式的正则表达式部分,则此<{1}}将被替换为退格,然后传递给正则表达式功能,它不会意味着那里的东西。所以你必须绝对传递带有反斜杠的\b,为此,你要么逃避反斜杠,要么生成字符串。

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

每个问题的编辑:

\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) 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) 通过匹配数字和正斜杠并使用连字符以不同的顺序替换它们来完成它的事情。由于re.sub在python中没有任何特殊含义,\d传递给\d表达式是否是粗略的。

第三个和第四个发生是因为你没有为替换表达式生成字符串。 re.sub\1\2在python中具有特殊含义,分别代表白色(或未填充)笑脸,黑色(填充)笑脸和心脏(如果角色不能显示,你会得到这些字符框&#39;)。因此,不是用捕获的组替换,而是用特定的字符替换字符串。

enter image description here

答案 2 :(得分:1)

并非所有\都会导致问题.Python有一些内置项目,如\b等。现在如果r不存在,python会认为\b是自己的对于正则表达式word boundary而言,当它与r模式一起使用时,\b保持不变。那就是外行语言。技术人员不多。\d不是特别内置于python中,因此即使没有r模式也是安全的。

在这里你可以see列表。这是python理解并将解释的列表。像\b\n而不是\d

在第一个print中,\d解释由正则表达式模块完成,而不是由python完成。在第二个print中,它由python完成。因为它在{{1它将按原样放置。

答案 3 :(得分:0)

我觉得上面的答案让它复杂化了。如果您正在运行re.search(),则您发送的字符串将通过两层进行解析:

  1. Python解释您编写的字符through this filter

  2. 然后,正则表达式会解释您编写的through its own filter字符。

  3. 他们按顺序发生。

    &#34; raw&#34;字符串语法r"\nlolwtfbbq"适用于想要绕过Python解释器的时候,它不会影响re

    >>> print "\nlolwtfbbq"
    
    lolwtfbbq
    >>> print r"\nlolwtfbbq"
    \nlolwtfbbq
    >>>
    

    请注意,第一个示例中会打印换行符,但实际字符\n会在第二个打印出来,因为它是原始的。

    您发送给re的任何字符串都会通过正则表达式解释器,因此要回答您的具体问题,\d表示&#34;数字0-9&#34;正则表达式。