字符串标志“ u”和“ r”到底是做什么的,什么是原始字符串文字?


652

当问这个问题时,我意识到我对原始字符串不了解很多。对于自称是Django培训师的人来说,这很糟糕。

我知道什么是编码,而且我知道u''自从得到Unicode以来,它独自做什么。

  • 但是究竟是r''什么呢?它产生什么样的字符串?

  • 最重要的是,该怎么ur''办?

  • 最后,有什么可靠的方法可以从Unicode字符串返回到简单的原始字符串?

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

Answers:


683

实际上并没有任何“原始字符串 ”。这里有原始的字符串文字,它们恰好是'r'在引号前用a标记的字符串文字。

“原始字符串文字”与字符串文字的语法略有不同,其中\反斜杠“”代表“只是反斜杠”(除非在引号之前否则会终止文字)- “转义序列”代表换行符,制表符,退格键,换页等。在普通的字符串文字中,每个反斜杠必须加倍,以避免被当作转义序列的开始。

之所以存在此语法变体,主要是因为正则表达式模式的语法带有反斜杠(但不会在末尾加重),所以语法比较繁琐(因此,上面的“ except”子句无关紧要),并且在避免将每个模式加倍时看起来会更好一些- - 就这样。表达本机Windows文件路径(用反斜杠代替其他平台上的常规斜杠)也引起了人们的欢迎,但这很少需要(因为正常斜杠在Windows上也可以正常工作)并且不完美(由于“ except”子句)以上)。

r'...'是一个字节串(在Python 2 *),ur'...'是Unicode字符串(再次,在Python 2 *),以及任何其他3种引用的也产生完全相同的类型字符串(因此,例如r'...'r'''...'''r"..."r"""..."""都是字节字符串,依此类推)。

不确定“ 返回 ”是什么意思-本质上没有前后方向,因为没有原始字符串类型,它只是一种表示完全正常的字符串对象,字节或Unicode的替代语法。

是的,在Python 2 *,u'...' 当然总是从刚不同'...'-前者是一个unicode字符串,后者是一个字节的字符串。文字表达的编码方式可能是完全正交的问题。

例如,考虑一下(Python 2.6):

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

Unicode对象当然会占用更多的存储空间(很短的字符串,很明显,;-差别很小)。


6
理解“ r”并不意味着任何类型或编码问题,它要简单得多。
e-satis

23
注意ru“ C:\ foo \ unstable”将失败,因为\ u是ru模式下的Unicode转义序列。r模式没有\ u。
Curtis Yallop 2014年

26
请注意,ur不是可交换的:ur'str'有效,不能ru'str'。(至少在win7的ipython 2.7.2中)
RafiK 2014年

7
刚刚测试过的r字符串并注意到,如果\ 是最后一个字符,则不会将其视为文字,而是转义结束引号,导致SyntaxError: EOL while scanning string literal。因此,\\ 对于\ 以反斜杠结尾的任何字符串的最终实例,仍必须使用它。
Enteleform's

1
python 3.x- sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(带有UTF8 lang的Ubuntu 16.04)。同样,type('cioa') == type(r'cioa') == type(u'cioa')。但是,原始字符串插值会有所不同,因此sys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber

177

python中有两种类型的字符串:传统str类型和较新unicode类型。如果您键入的字符串文字u前面不带,则将得到str存储8位字符的旧类型,而带u前面的将得到unicode可存储任何Unicode字符的较新类型。

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

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

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


谢谢,接受了。正如我所说,我知道unicode是什么,我不知道“ r”是什么意思,以及“ u”和“ r”的组合是什么。我知道更好,欢呼。
e-satis

6
反斜杠在原始字符串文字中不被视为文字,这就是r"\"语法错误的原因。

4
仅适用于Python2。–
PaulMcG

60

“原始字符串”表示将其存储为原样。例如,'\'只是一个反斜杠,而不是逃避


3
...除非它是字符串的最后一个字符,在这种情况下,它确实会转义结束引号。
jez

36

“ u”前缀表示该值具有类型unicode而不是str

带有“ r”前缀的原始字符串文字将转义其中的所有转义序列,因此len(r"\n")也是如此。2。由于它们转义了转义序列,因此您不能以单个反斜杠结束字符串文字:这不是有效的转义序列(例如r"\")。

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

您可以使用unicode原始字符串文字:

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

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

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


30

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

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

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

默认情况下,python会更喜欢str类型,但是如果您想将字符串存储为unicode类型,则可以将u放在像u'text'这样的文本前面,也可以通过调用unicode('text')来实现

所以ü只是打电话投的功能一小段路海峡Unicode的。而已!

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

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

现在,重要的部分:

您不能使用r来存储一个反斜杠,这是唯一的例外。因此,此代码将产生错误:r'\'

要存储反斜杠(仅一个),您需要使用“ \\”

如果要存储1个以上的字符,则仍可以使用r,r'\\'一样,将产生2个反斜杠,如您所愿。

我不知道r无法与一个反斜杠存储一起使用的原因,但至今尚未有人描述。我希望这是一个错误。


9
您会发现不仅r'\'非法,而且甚至不能'\'在任何字符串的尾部放一个。就像r'xxxxxx\'是非法字符串一样。
分叉

python 3呢?
克里斯(Krissh)

1
@Krissh所有python 3字符串都支持Unicode。其类型为str。更多为了更好地理解这里:medium.com/better-programming/...
off99555

4

也许这很明显,也许不是,但是您可以通过调用x = chr(92)来使字符串“ \”

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

4
x is y在python3中评估为True?
Habeeb Perwad

5
@HabeebPerwad,这是因为string interning。您永远不应依赖因实习而x is y发生评估的事实True。而是使用x == y(如果您不检查x和y是否与存储在单个内存位置的对象完全相同)。
Lucubrator

4

Unicode字符串文字

Unicode字符串文字(以前缀的字符串文字u)在Python 3中不再使用。它们仍然有效,但仅出于与Python 2 兼容的目的

原始字符串文字

如果要创建仅由易于键入的字符(例如英文字母或数字)组成的字符串文字,只需键入以下内容即可:'hello world'。但是,如果您还想包含一些其他奇特的字符,则必须使用一些解决方法。解决方法之一是转义序列。这样,例如,您只需\n在字符串文字中添加两个易于键入的字符,即可在字符串中表示新行。因此,当您打印'hello\nworld'字符串时,单词将被打印在单独的行上。非常方便!

另一方面,在某些情况下,您想创建一个包含转义序列的字符串文字,但又不希望它们由Python解释。您希望它们变得生硬。看下面的例子:

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

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

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

许多人期望原始字符串文字是原始的,因为“ 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\'都是无效的。

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.