“u”和“r”字符串前缀到底有什么作用,什么是原始字符串文字?

What exactly do "u" and "r" string prefixes do, and what are raw string literals?

提问人:Bite code 提问时间:1/18/2010 最后编辑:martineauBite code 更新时间:11/14/2023 访问量:661363

问:

在问这个问题时,我意识到我对原始字符串知之甚少。对于自称是 Django 培训师的人来说,这很糟糕。

我知道什么是编码,我知道只有编码才能做什么,因为我明白了什么是Unicode。u''

  • 但究竟做了什么?它会产生什么样的字符串?r''

  • 最重要的是,到底做了什么?ur''

  • 最后,有没有可靠的方法可以从Unicode字符串恢复到简单的原始字符串?

  • 啊,顺便说一句,如果你的系统和你的文本编辑器字符集设置为UTF-8,实际上有什么作用吗?u''

python unicode python-2.x rawstring

评论


答:

40赞 Roger Pate 1/18/2010 #1

“u”前缀表示值具有类型而不是 。unicodestr

带有“r”前缀的原始字符串文本可以转义其中的任何转义序列,2 也是如此。因为它们转义了转义序列,所以你不能用一个反斜杠结束字符串文本:这不是一个有效的转义序列(例如)。len(r"\n")r"\"

“Raw”不是类型的一部分,它只是表示值的一种方式。例如,和 是相同的值,就像 和 一样。"\\n"r"\n"320x200b100000

您可以有 unicode 原始字符串文本:

>>> u = ur"\n"
>>> print type(u), len(u)
<type 'unicode'> 2

源文件编码仅决定如何解释源文件,否则不会影响表达式或类型。但是,建议避免使用除 ASCII 以外的编码会更改含义的代码:

使用 ASCII(或 UTF-8,对于 Python 3.0)的文件不应具有编码 cookie。Latin-1(或 UTF-8)仅当注释或文档字符串需要提及需要 Latin-1 的作者姓名时才应使用;否则,使用 \x、\u 或 \U 转义是在字符串文本中包含非 ASCII 数据的首选方法。

224赞 Mark Byers 1/18/2010 #2

Python 2 中有两种类型的字符串:传统类型和较新类型。如果键入的字符串文本不带 in front,则会得到存储 8 位字符的旧类型,而 in front 则会得到可以存储任何 Unicode 字符的较新类型。strunicodeustruunicode

它根本不会改变类型,它只是改变了字符串文字的解释方式。如果没有 ,反斜杠将被视为转义字符。使用 时,反斜杠被视为文字。无论哪种方式,类型都是相同的。rrr

ur当然是一个 Unicode 字符串,其中反斜杠是文字反斜杠,而不是转义码的一部分。

您可以尝试使用该函数将 Unicode 字符串转换为旧字符串,但如果有任何 Unicode 字符无法在旧字符串中表示,则会出现异常。如果您愿意,您可以先用问号替换它们,但这当然会导致这些字符不可读。如果要正确处理 unicode 字符,则不建议使用该类型。str()str

评论

6赞 1/18/2010
在原始字符串文本中,反斜杠不被视为文本,这就是语法错误的原因。r"\"
8赞 PaulMcG 10/11/2018
仅适用于 Python 2。
1赞 pippo1980 1/12/2023
@PaulMcG print(r“\”) 也在 Python3 中给出错误:SyntaxError:扫描字符串文字时 EOL
872赞 Alex Martelli 1/18/2010 #3

实际上没有任何“原始字符串”;有原始字符串文本,它们正是在开始引号之前用 an 标记的字符串文本。'r'

“原始字符串文字”是字符串文字的语法略有不同,其中反斜杠 , 被理解为“只是一个反斜杠”(除非它正好在引号之前,否则会终止文本) -- 没有“转义序列”来表示换行符、制表符、退格键、表单馈送等。在普通的字符串文本中,每个反斜杠必须加倍,以避免被视为转义序列的开始。\

这种语法变体之所以存在,主要是因为正则表达式模式的语法中有很多反斜杠(但从来不会在末尾,所以上面的“except”子句无关紧要),当你避免将每个语法加倍时,它看起来会更好一些——仅此而已。它也获得了一些流行来表达本机 Windows 文件路径(使用反斜杠而不是像其他平台那样的常规斜杠),但这很少需要(因为普通斜杠在 Windows 上也大多工作正常)并且不完美(由于上面的“除外”子句)。

r'...'是一个字节字符串(在 Python 2.* 中),是一个 Unicode 字符串(同样,在 Python 2.* 中),其他三种引号中的任何一种也会产生完全相同类型的字符串(例如,、、、都是字节字符串,依此类推)。ur'...'r'...'r'''...'''r"..."r"""..."""

不知道你说的“返回”是什么意思 - 没有本质上的后退和前进方向,因为没有原始字符串类型,它只是一种替代语法来表达完全正常的字符串对象,字节或 unicode。

是的,在 Python 2.* 中,当然总是不同于 just -- 前者是 unicode 字符串,后者是字节字符串。对文本的编码可能表示是一个完全正交的问题。u'...''...'

例如,考虑(Python 2.6):

>>> sys.getsizeof('ciao')
28
>>> sys.getsizeof(u'ciao')
34

当然,Unicode 对象会占用更多的内存空间(显然,对于非常短的字符串来说,差异非常小;-)。

评论

10赞 Bite code 1/18/2010
理解“r”并不意味着任何类型或编码问题,它要简单得多。
34赞 Curtis Yallop 6/10/2014
请注意,ru“C:\foo\unstable” 将失败,因为 \u 是 ru 模式下的 unicode 转义序列。r 模式没有 \u。
38赞 RafiK 7/10/2014
请注意,并且不是交换的:有效,无效。(至少在 Win7 上的 iPython 2.7.2 中)urur'str'ru'str'
13赞 Enteleform 3/19/2017
刚刚测试了字符串并注意到,如果最后一个字符是最后一个字符,它不会被视为文字,而是转义了结束引号,导致 .因此,仍然必须用于任何以反斜杠结尾的字符串的最终实例。r\ SyntaxError: EOL while scanning string literal\\ \
2赞 Darren Weber 4/26/2018
python 3.x -(Ubuntu 16.04 与 UTF8 语言).同样地。但是,原始字符串插值会有所不同,因此sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')type('cioa') == type(r'cioa') == type(u'cioa')sys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
81赞 xiaolong 3/6/2012 #4

“原始字符串”表示它按显示方式存储。例如,只是一个反斜杠,而不是转义'\'

评论

24赞 jez 8/7/2019
...除非它是字符串的最后一个字符,在这种情况下,它确实会转义右引号。
41赞 chancdn 8/26/2015 #5

让我简单地解释一下: 在 python 2 中,您可以将字符串存储为 2 种不同的类型。

第一个是 ASCII,它是 python 中的 str 类型,它使用 1 字节的内存。(256个字符,主要存储英文字母和简单符号)

第二种类型是 UNICODE,它是 python 中的 unicode 类型。Unicode 存储所有类型的语言。

默认情况下,python 更喜欢 str 类型,但如果你想以 unicode 类型存储字符串,你可以把 u 放在文本前面,比如 u'text',或者你可以通过调用 unicode('text') 来做到这一点

因此,u 只是调用函数将 str 转换为 unicode 的捷径。就是这样!

现在 r 部分,你把它放在文本前面,告诉计算机文本是原始文本,反斜杠不应该是转义字符。r'\n' 不会创建新的行字符。它只是包含 2 个字符的纯文本。

如果要将 str 转换为 unicode 并将原始文本放入其中,请使用 因为 ru 会引发错误。

现在,重要的部分:

你不能使用 r 存储一个反斜杠,这是唯一的例外。 所以这个代码会产生错误:r'\'

要存储一个反斜杠(只有一个),您需要使用'\\'

如果要存储 1 个以上的字符,您仍然可以使用 r,例如 r'\\' 将产生 2 个反斜杠,如您预期的那样。

我不知道 r 不适用于一个反斜杠存储的原因,但还没有人描述原因。我希望这是一个错误。

评论

9赞 diverger 6/27/2016
你会注意到不仅是非法的,你甚至不能在任何字符串的尾巴上放一个。就像是非法的字符串一样。r'\''\'r'xxxxxx\'
0赞 Krissh 9/10/2019
Python 3 呢?
2赞 chancdn 9/10/2019
@Krissh 所有 python 3 字符串都支持 Unicode。其类型为 .在这里阅读更多内容以更好地理解:medium.com/better-programming/...str
0赞 qix 3/17/2022
r'\'给出了一个预期,并在以下部分注明: docs.python.org/3/reference/...: @Jeyekomon的另一个回答中也指出了这一点。SyntaxError: unterminated string literalEven in a raw literal, quotes can be escaped with a backslash, but the backslash remains in the result...
0赞 kirogasa 10/22/2022
为什么原始字符串(r-strings)不能以反斜杠结尾?(引用:更准确地说,它们不能以奇数个反斜杠结尾:末尾未配对的反斜杠转义了结束引号字符,留下一个未终止的字符串。)
7赞 Bomba Ps 5/15/2017 #6

也许这是显而易见的,也许不是,但你可以通过调用 x=chr(92) 来制作字符串 '\'

蟒蛇2

x=chr(92)
print type(x), len(x) # <type 'str'> 1

y='\\'
print type(y), len(y) # <type 'str'> 1

x==y   # True
x is y # False

蟒蛇3 (3.11.1)

x=chr(92)
print(type(x), len(x)) # <class 'str'> 1
# Note The Type Change To Class

y='\\'
print(type(y), len(y)) # <class 'str'> 1
# Note The Type Change To Class

x==y   # True
x is y # True
# Note this is now True

评论

5赞 Mohammed H 11/29/2017
x is y在 python3 中计算结果为 True?
8赞 Lucubrator 12/12/2017
@HabeebPerwad,那是因为字符串实习。你永远不应该依赖因为实习而碰巧评估的事实。请改用(如果您不检查 x 和 y 是否是存储在单个内存位置的完全相同的对象)。x is yTruex == y
18赞 Jeyekomon 7/23/2019 #7

Unicode 字符串文本

Python 3 中不再使用 Unicode 字符串文字(字符串文字前缀为 )。它们仍然有效,但只是为了与 Python 2 兼容。u

原始字符串文本

如果要创建仅由易于键入的字符(如英文字母或数字)组成的字符串文本,则只需键入它们即可:.但是,如果您还想包含一些更奇特的角色,则必须使用一些解决方法。'hello world'

解决方法之一是转义序列。例如,通过这种方式,只需在字符串文本中添加两个易于键入的字符,即可在字符串中表示新行。因此,当您打印字符串时,单词将打印在单独的行上。这非常方便!\n'hello\nworld'

另一方面,有时您可能希望将实际字符包含在字符串中 - 您可能不希望它们被解释为换行符。请看这些例子:\n

'New updates are ready in c:\windows\updates\new'
'In this lesson we will learn what the \n escape sequence does.'

在这种情况下,您可以像这样在字符串文字前面加上字符:Python 不会解释任何转义序列。字符串将完全按照您创建的方式打印。rr'hello\nworld'

原始字符串文字不完全是“原始”的吗?

许多人希望原始字符串文字是原始的,因为“Python忽略了引号之间的任何内容”。事实并非如此。Python 仍然识别所有转义序列,它只是不解释它们 - 它让它们保持不变。这意味着原始字符串文本仍然必须是有效的字符串文本

从字符串文本的词法定义

string     ::=  "'" stringitem* "'"
stringitem ::=  stringchar | escapeseq
stringchar ::=  <any source character except "\" or newline or the quote>
escapeseq  ::=  "\" <any source character>

很明显,包含裸引号字符 : 或以反斜杠结尾的字符串文本(原始或非原始)无效。'hello'world''hello world\'