我对以下代码中的原始字符串感到困惑:
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”也被当作一个数[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)
并得到如下输出:
您能具体解释一下这四种情况吗?
最佳答案
您对字符串和字符串文字之间的区别感到困惑。
字符串字面量是你放在 "
之间的内容或 '
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'
.字符串有时会令人困惑。
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
都是有效的转义序列,它们被替换为 unicode character其十进制表示由数字给出。这相当复杂,但基本上可以归结为:
\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+)'
,如第二个示例中所述。
关于python - Python 中的原始字符串和正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30164054/