“u”和“r”字符串标志到底是做啥的,啥是原始字符串文字?
Posted
技术标签:
【中文标题】“u”和“r”字符串标志到底是做啥的,啥是原始字符串文字?【英文标题】:What exactly do "u" and "r" string flags do, and what are raw string literals?“u”和“r”字符串标志到底是做什么的,什么是原始字符串文字? 【发布时间】:2011-01-06 02:26:12 【问题描述】:在询问this question 时,我意识到我对原始字符串知之甚少。对于自称是 Django 培训师的人来说,这很糟糕。
我知道什么是编码,而且我知道 u''
单独做了什么,因为我知道了什么是 Unicode。
但是r''
究竟做了什么?会产生什么样的字符串?
最重要的是,ur''
到底做了什么?
最后,有没有可靠的方法可以从 Unicode 字符串返回到简单的原始字符串?
啊,顺便问一下,如果您的系统和文本编辑器字符集设置为 UTF-8,u''
真的有什么作用吗?
【问题讨论】:
【参考方案1】:实际上没有任何“原始字符串”;有原始的字符串文字,它们正是在开头引号之前用'r'
标记的字符串文字。
“原始字符串文字”与字符串文字的语法略有不同,其中反斜杠 \
被视为“只是一个反斜杠”(除非它正好位于否则会终止的引号之前)文字)——没有“转义序列”来表示换行符、制表符、退格符、换页符等。在普通的字符串文字中,每个反斜杠都必须加倍以避免被视为转义序列的开始。
这种语法变体的存在主要是因为正则表达式模式的语法带有大量反斜杠(但从不在末尾,所以上面的“except”子句无关紧要)并且当你避免将每个都加倍时看起来会更好一些其中——仅此而已。表达本机 Windows 文件路径(使用反斜杠而不是其他平台上的常规斜杠)也获得了一定的普及,但这很少需要(因为普通斜杠在 Windows 上也能正常工作)并且不完美(由于“except”子句以上)。
r'...'
是字节字符串(在 Python 2.* 中),ur'...'
是 Unicode 字符串(同样,在 Python 2.* 中),其他三种引用也产生完全相同的类型字符串(例如r'...'
、r'''...'''
、r"..."
、r"""..."""
都是字节字符串,等等)。
不确定您所说的“返回返回”是什么意思 - 本质上没有前后方向,因为没有原始字符串 type,它只是一种替代语法表达完全正常的字符串对象,可能是字节或 unicode。
是的,在 Python 2.* 中,u'...'
是 当然总是与 '...'
不同——前者是 unicode 字符串,后者是字节字符串。可以用什么编码来表达文字是一个完全正交的问题。
例如,考虑(Python 2.6):
>>> sys.getsizeof('ciao')
28
>>> sys.getsizeof(u'ciao')
34
Unicode 对象当然会占用更多内存空间(很明显,对于非常短的字符串来说差异非常小;-)。
【讨论】:
理解“r”并不意味着任何类型或编码问题,它要简单得多。 注意 ru"C:\foo\unstable" 会失败,因为 \u 是 ru 模式下的 unicode 转义序列。 r模式没有\u。 请注意u
和 r
不可交换:ur'str'
有效,ru'str'
无效。 (至少在 win7 上的 ipython 2.7.2 中)
刚刚测试了r
字符串并注意到如果\
是最后一个字符,它将不会被视为文字而是转义结束引号,从而导致SyntaxError: EOL while scanning string literal
。因此,\\
仍然必须用于任何以反斜杠结尾的字符串中的 \
的最终实例。
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')
(带有 UTF8 语言的 Ubuntu 16.04)。同样,type('cioa') == type(r'cioa') == type(u'cioa')
。但是,原始字符串插值会有所不同,所以sys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
【参考方案2】:
python中有两种类型的字符串:传统的str
类型和较新的unicode
类型。如果你键入一个字符串文字,前面没有u
,你会得到旧的str
类型,它存储8 位字符,而前面有u
,你会得到新的unicode
类型,它可以存储任何Unicode 字符.
r
根本不改变类型,它只是改变了字符串文字的解释方式。如果没有r
,反斜杠将被视为转义字符。对于r
,反斜杠被视为文字。无论哪种方式,类型都是相同的。
ur
当然是一个 Unicode 字符串,其中反斜杠是文字反斜杠,而不是转义码的一部分。
您可以尝试使用str()
函数将Unicode 字符串转换为旧字符串,但如果有任何Unicode 字符无法在旧字符串中表示,则会出现异常。如果您愿意,您可以先用问号替换它们,但这当然会导致这些字符不可读。如果要正确处理unicode字符,不建议使用str
类型。
【讨论】:
谢谢,已接受。正如我所说,我知道 unicode 是什么,我不知道“r”是什么意思,以及“u”和“r”的组合是什么。我知道更好,干杯。 反斜杠在原始字符串文字中不被视为文字,这就是为什么r"\"
是一个语法错误。
仅适用于 Python 2。【参考方案3】:
'原始字符串' 表示它按其出现的方式存储。例如,'\'
只是一个 反斜杠 而不是 转义。
【讨论】:
...除非它是字符串的最后一个字符,在这种情况下它会转义右引号。【参考方案4】:“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
源文件编码只是决定如何解释源文件,它不影响表达式或类型。但是,recommended 是为了避免使用 ASCII 以外的编码会改变含义的代码:
使用 ASCII(或 UTF-8,对于 Python 3.0)的文件不应有编码 cookie。仅当注释或文档字符串需要提及需要 Latin-1 的作者姓名时,才应使用 Latin-1(或 UTF-8);否则,使用 \x、\u 或 \U 转义是在字符串文字中包含非 ASCII 数据的首选方式。
【讨论】:
【参考方案5】:让我简单解释一下: 在 python 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 并将原始文本放入其中,请使用 ur 因为 ru > 将引发错误。
现在,重要的部分:
您不能使用 r 存储一个反斜杠,这是唯一的例外。 所以这段代码会产生错误:r'\'
要存储反斜杠(只有一个),您需要使用 '\\'
如果您想存储超过 1 个字符,您仍然可以使用 r,例如 r'\\' 会如您预期的那样产生 2 个反斜杠。
我不知道 r 不能与一个反斜杠存储一起使用的原因,但尚未有人描述原因。我希望这是一个错误。
【讨论】:
你会注意到不仅r'\'
是非法的,你甚至不能在任何字符串的尾部添加一个'\'
。就像r'xxxxxx\'
是非法字符串一样。
python 3 怎么样?
@Krissh 所有 python 3 字符串都支持 Unicode。它的类型是str
。在此处阅读更多内容以更好地理解:medium.com/better-programming/…【参考方案6】:
Unicode 字符串字面量
Unicode 字符串文字(以 u
为前缀的字符串文字)在 Python 3 中为 no longer used。它们仍然有效,但在 Python 2 中为 just for compatibility purposes。
原始字符串字面量
如果您想创建一个仅包含易于输入的字符(如英文字母或数字)的字符串文字,您只需输入它们:'hello world'
。但是,如果您还想包含一些更奇特的字符,则必须使用一些解决方法。解决方法之一是Escape sequences。例如,通过这种方式,您可以通过在字符串文字中添加两个易于键入的字符 \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 仍然可以识别所有的转义序列,它只是不解释它们——而是让它们保持不变。这意味着原始字符串文字仍然必须是有效的字符串文字。
来自字符串文字的lexical definition:
string ::= "'" stringitem* "'"
stringitem ::= stringchar | escapeseq
stringchar ::= <any source character except "\" or newline or the quote>
escapeseq ::= "\" <any source character>
很明显,包含裸引号字符:'hello'world'
或以反斜杠结尾:'hello world\'
的字符串文字(原始或非原始)无效。
【讨论】:
【参考方案7】:也许这很明显,也许不是,但您可以通过调用 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
【讨论】:
x is y
在 python3 中的计算结果为 True?
@HabeebPerwad,那是因为string interning。您永远不应依赖 x is y
因为实习而恰好评估为 True
的事实。而是使用x == y
(如果您不检查 x 和 y 是否是存储在单个内存位置的完全相同的对象,即)。以上是关于“u”和“r”字符串标志到底是做啥的,啥是原始字符串文字?的主要内容,如果未能解决你的问题,请参考以下文章