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

标签 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”也被当作一个数[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/

相关文章:

python - 如果我在 __init__ 时没有可用的所有实例变量值,我可以创建一个对象吗?

Python游戏结束屏幕不接受输入

python - 使用 Python 的 Microsoft Graph API 请求 : "Insufficient privileges to complete the operation" error when making simple call

python - 在 Python 中导航目录

java - 如何使用 java 正则表达式验证字符串?

python - impala shell,带大写字母的 shell 命令

c++ - C# @ 符号前缀字符串的 C++ 等价物是什么?

php - 用户生成的内联 css 是否存在任何安全风险

regex - 如何使用 rexex (Python) 将带有未闭合括号的数字与闭合括号进行匹配

swift - 快速转义单引号