.. productionlist::
bytesliteral: `bytesprefix`(`shortbytes` | `longbytes`)
- bytesprefix: "b" | "B" | "br" | "Br" | "bR" | "BR"
+ bytesprefix: "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB"
shortbytes: "'" `shortbytesitem`* "'" | '"' `shortbytesitem`* '"'
longbytes: "'''" `longbytesitem`* "'''" | '"""' `longbytesitem`* '"""'
shortbytesitem: `shortbyteschar` | `bytesescapeseq`
literal characters. As a result, in string literals, ``'\U'`` and ``'\u'``
escapes in raw strings are not treated specially.
+ .. versionadded:: 3.3
+ The ``'rb'`` prefix of raw bytes literals has been added as a synonym
+ of ``'br'``.
+
In triple-quoted strings, unescaped newlines and quotes are allowed (and are
retained), except that three unescaped quotes in a row terminate the string. (A
"quote" is the character used to open the string, i.e. either ``'`` or ``"``.)
There are four types of string literals:
- 'abc' -- normal str
- r'abc' -- raw str
- b'xyz' -- normal bytes
- br'xyz' -- raw bytes
+ 'abc' -- normal str
+ r'abc' -- raw str
+ b'xyz' -- normal bytes
+ br'xyz' | rb'xyz' -- raw bytes
The difference between normal and raw strings is of course that in a
raw string, \ escapes (while still used to determine the end of the
def test_eval_bytes_raw(self):
self.assertEqual(eval(""" br'x' """), b'x')
+ self.assertEqual(eval(""" rb'x' """), b'x')
self.assertEqual(eval(r""" br'\x01' """), b'\\' + b'x01')
+ self.assertEqual(eval(r""" rb'\x01' """), b'\\' + b'x01')
self.assertEqual(eval(""" br'\x01' """), byte(1))
+ self.assertEqual(eval(""" rb'\x01' """), byte(1))
self.assertEqual(eval(r""" br'\x81' """), b"\\" + b"x81")
+ self.assertEqual(eval(r""" rb'\x81' """), b"\\" + b"x81")
self.assertRaises(SyntaxError, eval, """ br'\x81' """)
+ self.assertRaises(SyntaxError, eval, """ rb'\x81' """)
self.assertEqual(eval(r""" br'\u1881' """), b"\\" + b"u1881")
+ self.assertEqual(eval(r""" rb'\u1881' """), b"\\" + b"u1881")
self.assertRaises(SyntaxError, eval, """ br'\u1881' """)
+ self.assertRaises(SyntaxError, eval, """ rb'\u1881' """)
+ self.assertRaises(SyntaxError, eval, """ bb'' """)
+ self.assertRaises(SyntaxError, eval, """ rr'' """)
+ self.assertRaises(SyntaxError, eval, """ brr'' """)
+ self.assertRaises(SyntaxError, eval, """ bbr'' """)
+ self.assertRaises(SyntaxError, eval, """ rrb'' """)
+ self.assertRaises(SyntaxError, eval, """ rbb'' """)
def check_encoding(self, encoding, extra=""):
modname = "xx_" + encoding.replace("-", "_")
/* Identifier (most frequent token!) */
nonascii = 0;
if (is_potential_identifier_start(c)) {
- /* Process b"", r"" and br"" */
- if (c == 'b' || c == 'B') {
- c = tok_nextc(tok);
- if (c == '"' || c == '\'')
- goto letter_quote;
- }
- if (c == 'r' || c == 'R') {
+ /* Process b"", r"", br"" and rb"" */
+ int saw_b = 0, saw_r = 0;
+ while (1) {
+ if (!saw_b && (c == 'b' || c == 'B'))
+ saw_b = 1;
+ else if (!saw_r && (c == 'r' || c == 'R'))
+ saw_r = 1;
+ else
+ break;
c = tok_nextc(tok);
if (c == '"' || c == '\'')
goto letter_quote;