ChatGPT解决这个技术问题 Extra ChatGPT

为什么 Python 的原始字符串文字不能以单个反斜杠结尾?

从技术上讲,任何奇数个反斜杠,如 the documentation 中所述。

>>> r'\'
  File "<stdin>", line 1
    r'\'
       ^
SyntaxError: EOL while scanning string literal
>>> r'\\'
'\\\\'
>>> r'\\\'
  File "<stdin>", line 1
    r'\\\'
         ^
SyntaxError: EOL while scanning string literal

似乎解析器可以将原始字符串中的反斜杠视为常规字符(这不是原始字符串的全部内容吗?),但我可能遗漏了一些明显的东西。

看起来这现在是一个 faq。当你问这个问题时可能不是。我知道您引用的文档说的几乎相同,但我只是想我会添加另一个文档来源。
@oob并且该文档清楚地解释了它们主要用于正则表达式(不应以反斜杠结尾)而不是Windows路径,应该。

F
Faheem Mitha

关于 python 的原始字符串的全部误解是,大多数人认为反斜杠(在原始字符串中)和其他所有字符一样只是一个常规字符。它不是。理解的关键是这个python的教程序列:

当存在 'r' 或 'R' 前缀时,反斜杠后面的字符将不加更改地包含在字符串中,并且所有反斜杠都保留在字符串中

所以反斜杠后面的任何字符都是原始字符串的一部分。一旦解析器输入原始字符串(非 Unicode 字符串)并遇到反斜杠,它就知道有 2 个字符(反斜杠和后面的字符)。

这边走:

r'abc\d' 包含 a, b, c, \, d r'abc\'d' 包含 a, b, c, \, ', d r'abc\'' 包含 a, b, c, \, '

和:

r'abc\' 包含 a, b, c, \, ' 但现在没有终止引号。

最后一个案例表明,根据文档,现在解析器找不到结束引号,因为您在上面看到的最后一个引号是字符串的一部分,即反斜杠不能在此处最后,因为它会“吞噬”字符串结束字符。


所以我了解机制,但为什么呢?为什么这样实施?我看不出这背后的理性。所以上面的解释告诉我们,本质上原始字符串使引号内的所有内容都作为自身,但反斜杠不能不作为最后一个字符出现。所以为什么?这样就可以确保它不能用作文件路径字符串????
当我进一步阅读页面时,我发现它的目的是在字符串中加上引号,那么为什么我不能只放一个引号而我必须在它前面放一个反斜杠呢?我想这一定是有原因的,可能与正则表达式有关?
我认为如果它与正则表达式无关,这是一个设计缺陷,因为还有其他选项可以采用,例如双引号,例如在大多数 .csv 文件中使用 "" 表示 "。x = r"I have ""an apple""" 代表 I have "an apple" . 一个问题是 python 允许 a="a""b"a="a" "b" 导致 a="ab"。所以要使用双引号,python 需要禁止 a="a""b" 的用例。
我建议再包括一个:r'abc\\'包括a、b、c、\、\
c
cdleary

原因在我以粗体突出显示的那部分的部分中进行了解释:

字符串引号可以用反斜杠转义,但反斜杠保留在字符串中;例如,r"\"" 是由两个字符组成的有效字符串文字:反斜杠和双引号;r"\" 不是有效的字符串文字(即使原始字符串也不能以奇数个反斜杠结尾)。具体来说,原始字符串不能以单个反斜杠结尾(因为反斜杠会转义后面的引号字符)。另请注意,单个反斜杠后跟换行符被解释为这两个字符作为字符串的一部分,而不是作为续行.

所以原始字符串不是 100% 原始的,还有一些基本的反斜杠处理。


哇哦……好奇怪。不错的收获。 r'\'' == "\\'" 是有道理的,但转义字符有效果而不消失仍然很奇怪。
@ihightower 这可能适用于文件系统路径,但反斜杠还有其他用途。对于文件系统路径,不要硬编码分隔符。使用 'os.path.sep',或更好的 'os.path' 的更高级别的功能。 (或“pathlib”,如果可用)
注意:解决方法是使用相邻的文字连接。 r"foo\bar\baz" "\\"(如果有歧义,用括号括起来)将在编译时创建一个文字,其中的第一部分是原始的,只有最后一点是非原始的,以允许尾部反斜杠。
IMO 这只是重申了这个问题(什么是允许/将起作用,什么不是),而没有说明为什么要这样设计。有一个 FAQ entry 可以解释原因(原始字符串是为特定目的而设计的,并且在该目的的上下文中是有意义的)。
那么原始字符串有什么意义呢?似乎是这个概念的阴暗实现。
h
hasen

它就是这样儿的!我认为它是 python 中的小缺陷之一!

我认为没有充分的理由,但绝对不是解析;用 \ 作为最后一个字符来解析原始字符串真的很容易。

问题是,如果您允许 \ 成为原始字符串中的最后一个字符,那么您将无法将 " 放入原始字符串中。似乎 python 使用了 allow " 而不是允许 \ 作为最后一个字符。

但是,这不应该造成任何麻烦。

如果您担心无法轻松编写诸如 c:\mypath\ 之类的 windows 文件夹路径,请不要担心,因为您可以将它们表示为 r"C:\mypath",并且,如果您需要附加子目录名称,请不要这样做它与字符串连接,因为无论如何这不是正确的方法!使用 os.path.join

>>> import os
>>> os.path.join(r"C:\mypath", "subfolder")
'C:\\mypath\\subfolder'

很好的辅助材料。 :-) 但魔鬼的拥护者:有时您想通过附加路径分隔符来区分文件路径和目录路径。 os.path.join 的好处在于它会折叠它们: assert os.path.join('/home/cdleary/', 'foo/', 'bar/') == '/home/cdleary/foo/酒吧/'
但它并没有产生(技术)差异! os.path.isdir 会告诉你某个路径是否是目录(文件夹)
是的,这只是为了向阅读代码的人表明您希望路径是目录还是文件。
Windows 上的约定是文件总是有扩展名。根本不可能(在正常情况下)有一个带有诸如 c:\path\data 路径的文本文件
..或者您可以将它们表示为“c:/mypath”并完全忘记您的反斜杠问题:-)
C
Charles Beattie

为了让你用斜杠结束原始字符串,我建议你可以使用这个技巧:

>>> print r"c:\test"'\\'
test\

f
famousgarkin

另一个技巧是使用 chr(92) 计算结果为“\”。

我最近不得不清理一串反斜杠,以下是诀窍:

CleanString = DirtyString.replace(chr(92),'')

我意识到这并没有解决“为什么”,但该线程吸引了许多人寻找解决直接问题的方法。


但是如果原始字符串包含反斜杠怎么办?
chr(92) 非常晦涩难懂,最好使用 "\\" (带反斜杠的非原始字符串)
B
Brian R. Bondy

由于 \" 允许在原始字符串中。那么它不能用于标识字符串文字的结尾。

为什么在遇到第一个“时不停止解析字符串文字?

如果是这种情况,那么 \" 将不允许在字符串文字中。但它是。


确切地。 Python 设计者可能评估了这两种选择的可能性:双引号原始字符串中任意位置的两个字符序列 \",或在双引号原始字符串末尾的 \。使用统计信息必须有利于任何地方的两个字符序列而不是最后的一个字符序列。
G
Gumbo

r'\' 语法不正确的原因是,尽管字符串表达式是原始的,但使用的引号(单引号或双引号)总是必须转义,否则它们会标记引号的结尾。所以如果你想在单引号字符串中表达单引号,除了使用\'之外别无他法。同样适用于双引号。

但你可以使用:

'\\'

c
cdleary

另一位后来删除了他们的答案的用户(不确定他们是否希望得到认可)建议 Python 语言设计者可以通过使用相同的解析规则并将转义字符扩展为原始形式作为事后的想法来简化解析器设计(如果文字被标记为原始)。

我认为这是一个有趣的想法,并将其作为社区 wiki 供后代使用。


但它可能会让您避免使用两个单独的字符串文字解析器代码路径。
佚名

从 C 开始,我很清楚单个 \ 用作转义字符,允许您将特殊字符(例如换行符、制表符和引号)放入字符串中。

这确实不允许 \ 作为最后一个字符,因为它会转义 " 并使解析器窒息。但正如前面指出的 \ 是合法的。


是的 - 问题的核心是原始字符串将 \ 视为文字而不是转义序列的开始。奇怪的是,尽管被视为文字字符,但它仍然具有用于引用的转义属性。
佚名

一些技巧 :

1)如果您需要为路径操作反斜杠,那么标准 python 模块 os.path 是您的朋友。例如 :

os.path.normpath('c:/folder1/')

2)如果您想在其中构建带有反斜杠的字符串,但在字符串的末尾没有反斜杠,那么原始字符串是您的朋友(在您的文字字符串之前使用'r'前缀)。例如 :

r'\one \two \three'

3)如果您需要在变量 X 中使用反斜杠作为字符串前缀,那么您可以这样做:

X='dummy'
bs=r'\ ' # don't forget the space after backslash or you will get EOL error
X2=bs[0]+X  # X2 now contains \dummy

4)如果您需要在末尾创建一个带有反斜杠的字符串,则将提示 2 和 3 结合起来:

voice_name='upper'
lilypond_display=r'\DisplayLilyMusic \ ' # don't forget the space at the end
lilypond_statement=lilypond_display[:-1]+voice_name

现在 lilypond_statement 包含 "\DisplayLilyMusic \upper"

蟒蛇万岁! :)

n3on


这些都没有回答“为什么”的问题,但不应该使用#3 和#4。切片和添加字符串通常是不好的做法,您应该更喜欢 r'\dummy' 用于#3(效果很好)和 ' '.join([r'\DisplayLilyMusic', r'\upper']) 到 #4。
原因是字符串是不可变的,并且每个切片/连接都会创建一个新的不可变字符串对象,该对象通常会被丢弃。最好将它们全部累积并使用 str.join(components) 一步将它们连接在一起
哦,哎呀-误解了您对#3的意思。我认为有一个简单的 '\\' + X 比创建一个字符串来分割它更可取。
只需 find os.path.normpath 将删除尾部反斜杠...那么我应该如何将文件名连接到路径中...
E
Ed Avis

尽管有其作用,但即使是原始字符串也不能以单个反斜杠结尾,因为反斜杠转义了后面的引号字符 - 您仍然必须转义周围的引号字符才能将其嵌入字符串中。也就是说,r"...\" 不是一个有效的字符串字面量——原始字符串不能以奇数个反斜杠结尾。如果您需要以单个反斜杠结束原始字符串,则可以使用两个并切掉第二个。


你在引用什么?
似乎来自apprize.best/python/learning_1/8.html,没有署名。
B
BossaNova

我遇到了这个问题,并找到了一个对某些情况有好处的部分解决方案。尽管 python 不能以单个反斜杠结束字符串,但可以将其序列化并保存在末尾带有单个反斜杠的文本文件中。因此,如果您需要在计算机上保存带有单个反斜杠的文本,则可以:

x = 'a string\\' 
x
'a string\\' 

# Now save it in a text file and it will appear with a single backslash:

with open("my_file.txt", 'w') as h:
    h.write(x)

顺便说一句,如果您使用 python 的 json 库转储它,它不适用于 json。

最后,我使用 Spyder,我注意到如果我通过在变量资源管理器中双击变量名称在蜘蛛的文本编辑器中打开变量,它会显示一个反斜杠,并且可以通过这种方式复制到剪贴板(不是对大多数需求非常有帮助,但可能对某些需求有帮助..)。