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

在问这个问题时,我意识到我对原始字符串了解不多。对于一个自称是Django教练的人来说,这太糟糕了。

我知道编码是什么,我知道u''单独做了什么,因为我得到了什么是Unicode。

  • 但是r''到底做了什么?它会导致什么样的字符串?

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

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

  • 啊,顺便说一下,如果您的系统和文本编辑器字符集设置为UTF-8,u''实际上会做任何事情吗?

610315 次浏览

“u”前缀表示值的类型为unicode而不是str

带有“r”前缀的原始字符串文字转义其中的任何转义序列,因此len(r"\n")是2。因为它们转义转义序列,所以您不能以单个反斜杠结束字符串文字:这不是有效的转义序列(例如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数据的首选方式。

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

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

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

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

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

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

这种语法变体的存在主要是因为正则表达式模式的语法带有大量反斜杠(但从来没有在最后,所以上面的“除了”子句并不重要),并且当您避免将每个反斜杠加倍时,它看起来会更好-仅此而已。它还获得了一些流行来表达本机Windows文件路径(使用反斜杠而不是像其他平台上的正则斜杠),但这很少需要(因为普通斜杠在Windows上也可以正常工作)并且不完美(由于上面的“除了”子句)。

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

不确定你所说的“去”是什么意思-没有本质上的后退和前进方向,因为没有原始字符串类型,它只是表达完全正常的字符串对象,字节或Unicode的替代语法。

是的,在Python 2.*中,u'...'当然总是与'...'不同——前者是一个Unicode字符串,后者是一个字节字符串。文字可能用什么编码来表达是一个完全正交的问题。

例如,考虑(Python 2.6):

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

Unicode对象当然需要更多的内存空间(显然,非常短的字符串差异很小;-)。

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

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

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

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

默认情况下,python更喜欢str类型,但如果您想将字符串存储在Unicode类型中,您可以将u放在删除文本之类的文本前面,或者您可以通过调用Unicode('text')来做到这一点

所以u只是调用函数将str转换为Unicode的一种简短方法。就是这样!

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

如果您想将str转换为Unicode并在其中放置原始文本,请使用ur,因为ru会引发错误。

现在,重要的部分:

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

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

如果你想存储超过1个字符,你仍然可以使用r,就像r'\\'会像你预期的那样产生2个反斜杠。

我不知道为什么r不适用于一个反斜杠存储,但原因还没有被任何人描述。我希望这是一个bug。

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

x=chr(92)print type(x), len(x) # <type 'str'> 1y='\\'print type(y), len(y) # <type 'str'> 1x==y   # Truex is y # False

Unicode字符串文字

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

原始字符串文字

如果你想创建一个字符串字面量,只包含容易键入的字符,如英文字母或数字,你可以简单地键入它们:'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.'

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

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

许多人期望原始字符串文字在某种意义上是原始的“引号之间的任何内容都被Python忽略”。这不是真的。Python仍然识别所有的转义序列,它只是不解释它们-它让它们保持不变。这意味着原始字符串文字仍然必须是有效的字符串文字

从字符串文字的词汇定义

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

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