在问这个问题时,我意识到我对原始字符串不太了解。对于自称是Django教练的人来说,这太糟糕了。
我知道什么是编码,我知道只有“u”才能做什么,因为我得到了什么是Unicode。
但“r”到底做什么?它会产生什么样的字符串?最重要的是,你到底在干什么?最后,有没有可靠的方法可以从Unicode字符串返回到简单的原始字符串?哦,顺便问一下,如果您的系统和文本编辑器字符集设置为UTF-8,那么您实际上做了什么吗?
在问这个问题时,我意识到我对原始字符串不太了解。对于自称是Django教练的人来说,这太糟糕了。
我知道什么是编码,我知道只有“u”才能做什么,因为我得到了什么是Unicode。
但“r”到底做什么?它会产生什么样的字符串?最重要的是,你到底在干什么?最后,有没有可靠的方法可以从Unicode字符串返回到简单的原始字符串?哦,顺便问一下,如果您的系统和文本编辑器字符集设置为UTF-8,那么您实际上做了什么吗?
当前回答
实际上没有任何“原始字符串”;有一些原始字符串文字,它们正好是在开头引号前用“r”标记的字符串文字。
“原始字符串文字”是字符串文字的一种稍有不同的语法,其中反斜杠\被视为“仅反斜杠”的意思(除非它正好在引号之前,否则会终止文字)——没有“转义序列”来表示换行符、制表符、退格符、表单提要等。在正常字符串文字中,每个反斜杠必须加倍,以避免作为转义序列的开始。
这种语法变体之所以存在,主要是因为正则表达式模式的语法中有大量的反斜杠(但永远不会在末尾,所以上面的“except”子句无关紧要),并且当您避免将它们中的每一个都加倍时,它看起来会更好一些——仅此而已。它还流行于表示本机Windows文件路径(使用反斜杠代替其他平台上的正斜杠),但这很少需要(因为通常的斜杠在Windows上也很好),而且不完美(由于上面的“except”子句)。
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对象占用了更多的内存空间(很明显,对于非常短的字符串,差异很小;-)。
其他回答
Unicode字符串文字
Python 3中不再使用Unicode字符串文字(前缀为u的字符串文字)。它们仍然有效,但只是为了与Python 2兼容。
生字符串
如果你想创建一个字符串文字,它只包含英文字母或数字等容易键入的字符,你可以简单地键入它们:“helloworld”。但是,如果您还想包含一些更具异国情调的角色,则必须使用一些变通方法。
其中一个解决方法是Escape序列。这样,例如,只需在字符串文字中添加两个易于键入的字符,就可以在字符串中表示新行。因此,当您打印“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 | escapeseq
stringchar ::= <any source character except "\" or newline or the quote>
escapeseq ::= "\" <any source character>
很明显,包含空引号字符“hello'world”或以反斜杠“helloworld\”结尾的字符串文本(原始或非原始)无效。
“原始字符串”意味着它按显示方式存储。例如,“\”只是反斜杠而不是转义。
Python 2中有两种字符串类型:传统的str类型和较新的unicode类型。如果键入一个字符串文本,前面没有u,则会得到存储8位字符的旧str类型,而前面有u,则得到可以存储任何unicode字符的新unicode类型。
r根本不改变类型,它只是改变字符串文本的解释方式。如果没有r,反斜杠将被视为转义字符。使用r时,反斜杠被视为文字。无论哪种方式,类型都是相同的。
ur当然是Unicode字符串,其中反斜杠是字面反斜杠,而不是转义码的一部分。
您可以尝试使用str()函数将Unicode字符串转换为旧字符串,但如果有任何Unicode字符无法在旧字符串中表示,则会出现异常。如果你愿意,你可以先用问号代替它们,但这当然会导致这些字符无法阅读。如果要正确处理unicode字符,建议不要使用str类型。
“u”前缀表示值的类型为unicode而不是str。
带“r”前缀的原始字符串文本对其中的任何转义序列进行转义,因此len(r“\n”)为2。因为它们是转义序列,所以不能用一个反斜杠结束字符串文字:这不是有效的转义序列(例如r“\”)。
“Raw”不是类型的一部分,它只是表示值的一种方式。例如,“\\n”和r“\n”是相同的值,就像32、0x20和0b100000是相同的。
可以使用unicode原始字符串文字:
>>> u = ur"\n"
>>> print type(u), len(u)
<type 'unicode'> 2
源文件编码只决定如何解释源文件,否则不会影响表达式或类型。但是,建议避免使用非ASCII编码会改变含义的代码:
使用ASCII(或UTF-8,对于Python 3.0)的文件不应有编码cookie。只有当注释或文档字符串需要提及需要拉丁-1的作者名称时,才应使用拉丁-1(或UTF-8);否则,使用\x、\u或\u转义是在字符串文本中包含非ASCII数据的首选方式。
实际上没有任何“原始字符串”;有一些原始字符串文字,它们正好是在开头引号前用“r”标记的字符串文字。
“原始字符串文字”是字符串文字的一种稍有不同的语法,其中反斜杠\被视为“仅反斜杠”的意思(除非它正好在引号之前,否则会终止文字)——没有“转义序列”来表示换行符、制表符、退格符、表单提要等。在正常字符串文字中,每个反斜杠必须加倍,以避免作为转义序列的开始。
这种语法变体之所以存在,主要是因为正则表达式模式的语法中有大量的反斜杠(但永远不会在末尾,所以上面的“except”子句无关紧要),并且当您避免将它们中的每一个都加倍时,它看起来会更好一些——仅此而已。它还流行于表示本机Windows文件路径(使用反斜杠代替其他平台上的正斜杠),但这很少需要(因为通常的斜杠在Windows上也很好),而且不完美(由于上面的“except”子句)。
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对象占用了更多的内存空间(很明显,对于非常短的字符串,差异很小;-)。