为什么在Python字符串中3个反斜杠等于4个?


90

你能告诉我为什么'?\\\?'=='?\\\\?'True吗?这让我发疯,我找不到合理的答案...

>>> list('?\\\?')
['?', '\\', '\\', '?']
>>> list('?\\\\?')
['?', '\\', '\\', '?']

8
后者没有逃脱任何东西,所以最终逃脱了自己的生命
Padraic Cunningham

1
list()甚至不需要包括:>>> '?\\\?' '?\\\\?'
daboross '16

@PadraicCunningham它不会“最终逃脱”。那有什么意思?
user253751 '16

有趣的是,原因是它们都等于两个反斜线:-)
RemcoGerlich '16

@immibis,这正是正在发生的事情。您知道repr和str之间的区别吗?尝试同时在字符串中使用两个反斜杠进行打印,这可能会变得很清楚
Padraic Cunningham

Answers:


84

基本上,因为python在反斜杠处理中稍微宽容。从https://docs.python.org/2.0/ref/strings.html引用:

与标准C不同,所有无法识别的转义序列都保留在字符串中不变,即,反斜杠保留在字符串中

(强调原件)

因此,在python中,并不是三个反斜杠等于四个,而是当您在反斜杠后面加上字符时?,这两个字符一起成为两个字符,因为\?这不是公认的转义序列。


6
那是宽容的反面。宽容是大多数其他人的行为,“如果您反斜杠不需要的字符,则反斜杠不会执行任何操作”。再加上另一种约定(反斜杠字母数字可能使它们特殊,但是反斜杠标点始终使它变得非特殊),您将获得一个非常好的属性,可以通过对所有标点进行反斜杠来安全地对字符串进行放宽,而不必知道哪些字符是特殊的交错-Python缺少的属性。
hobbs's

24
不,宽大的反面是当您使用无法识别的反斜杠转义符时引发错误。(就像几乎每种编译语言一样。请记住,Python的字符串处理基本上是“像C一样,只不过我们在传递无效的反斜杠转义时不会炸开”) -用作分隔符的所有内容,并反斜杠本身。我不明白很难记住这两种说法。
丹尼尔·马丁

@DanielMartin在某些语言中,分隔符用作其自己的转义符(例如'escape''d')。您甚至不必在那里记住其他字符!
SztupY

1
哦,等等,我想标准的pascal也使用了该系统-参见nyx.net/~gthompso/self_pasc.txt
Daniel Martin

1
@DanielMartin SQL也是如此。
2016年

30

这是因为,如果组合表示有效的转义序列,则反斜杠将充当紧跟其后的字符的转义字符。这里列出了十几个转义序列。它们包括明显的字符\n,例如换行符,水平制表符\t,回车符,\r以及较晦涩的字符\N{...},例如使用命名的unicode字符,例如\N{WAVY DASH},表示unicode字符\u3030。但是,关键点在于,如果不知道转义序列,则字符序列将保留在字符串中。

问题的一部分可能还在于Python解释器的输出误导了您。这是因为显示时反斜杠已转义。但是,如果打印这些字符串,则会看到多余的反斜杠消失。

>>> '?\\\?'
'?\\\\?'
>>> print('?\\\?')
?\\?
>>> '?\\\?' == '?\\?'    # I don't know why you think this is True???
False
>>> '?\\\?' == r'?\\?'   # but if you use a raw string for '?\\?'
True
>>> '?\\\\?' == '?\\\?'  # this is the same string... see below
True

对于您的特定示例,在第一种情况下'?\\\?',第一个\转义符转义第二个反斜杠而留下单个反斜杠,但是第三个反斜杠仍保留为反斜杠,因为\?这不是有效的转义序列。因此,结果字符串为?\\?

对于第二种情况'?\\\\?',第一个反斜杠转义第二个反斜杠,而第三个反斜杠转义第四个反斜杠,结果为string ?\\?

因此,这就是三个反斜杠与四个反斜杠相同的原因:

>>> '?\\\?' == '?\\\\?'
True

如果要创建带有3个反斜杠的字符串,可以转义每个反斜杠:

>>> '?\\\\\\?'
'?\\\\\\?'
>>> print('?\\\\\\?')
?\\\?

否则您可能会发现“原始”字符串更容易理解:

>>> r'?\\\?'
'?\\\\\\?'
>>> print(r'?\\\?')
?\\\?

这将对字符串文字进行转义序列处理。有关更多详细信息,请参见字符串文字


你说的没错'?\\\?'=='?\\?'False,我输错了。这应该是'?\\\?'=='?\\\\?'因为这个问题表明,我已经纠正它。
kozooh'2

13

由于\x字符串中,当x不是特别backslashable字符等中的一个nrt0,等,评估一个反斜杠,然后一个一个串x

>>> '\?'
'\\?'

7

在python词法分析页面中的字符串常量下:https : //docs.python.org/2/reference/lexical_analysis.html

有一张表列出了所有可识别的转义序列。

\\是一个转义序列,它=== \

\?不是转义序列,而是=== \?

因此,“ \\\\”是“ \\”,后跟“ \\”即“ \\”(两个转义的\)

“ \\\”是“ \\”,后跟“ \”,后者也是“ \\”(一个转义的\和一个原始的\)

同样,应该注意的是,与某些其他语言不同,python不能区分字符串文字周围的单引号和双引号。

所以'String'和“ String”在python中是完全一样的,它们不影响转义序列的解释。


1

mhawke的答案几乎涵盖了这一点,我只是想以一种更为简洁的形式来重述它,并用最少的例子来说明这种行为。

我想添加的一件事是转义处理从左到右移动,因此\n首先找到反斜杠,然后寻找要转义的字符,然后找到n并转义它。\\n找到第一个反斜杠,找到第二个反斜杠并将其转义,然后找到n并将其视为文字n;\?查找反斜杠并查找要转义的字符,查找?无法转义\的字符,因此将其视为文字反斜杠。

正如mhawke所指出的,这里的关键是交互式解释器在显示字符串时转义反斜杠。我猜这是为了确保从解释器复制到代码编辑器的文本字符串是有效的python字符串。然而,在这种情况下,为方便起见,这种余地引起了混乱。

>>> print('\?') # \? is not a valid escape code so backslash is left as-is
\?
>>> print('\\?') # \\ is a valid escape code, resulting in a single backslash
'\?'

>>> '\?' # same as first example except that interactive interpreter escapes the backslash
\\?
>>> '\\?' # same as second example, backslash is again escaped
\\?
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.