Какая разница между шестнадцатеричным кодом (\ x) и символом unicode (\ u)?

От ?Quotes:

\ xnn с заданным шестнадцатеричным кодом (1 или 2 шестнадцатеричных разряда)
\ unnn Unicode-символ с заданным кодом (1--4 шестнадцатеричных цифр)

В случае, когда символ Юникода имеет только одну или две цифры, я ожидал бы, что эти символы будут одинаковыми. На самом деле, один из примеров на странице справки ?Quotes показывает:

"\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21"
## [1] "Hello World!"
"\u48\u65\u6c\u6c\u6f\u20\u57\u6f\u72\u6c\u64\u21"
## [1] "Hello World!"

Однако, под Linux, при попытке распечатать знак фунта, я вижу

cat("\ua3")
## £
cat("\xa3")
## �

То есть шестнадцатеричный код \x не отображается правильно. (Это поведение сохранялось в любой локали, которую я пробовал.) В Windows 7 обе версии показывают знак фунта.

Если я конвертирую в целое и обратно, тогда знак фунта отображается правильно в Linux.

cat(intToUtf8(utf8ToInt("\xa3")))
## £

Кстати, это не работает под Windows, так как utf8ToInt("\xa3") возвращает NA.

Некоторые \x символы возвращают NA под Windows, но вызывают ошибку в Linux. Например:

utf8ToInt("\xf0")
## Error in utf8ToInt("\xf0") : invalid UTF-8 string

("\uf0" является допустимым символом.)

Эти примеры показывают, что существуют некоторые различия между формами символов \x и \u, которые кажутся специфичными для ОС, но я не вижу никакой логики в том, как они определены.

В чем разница между этими двумя символьными формами?

Ответы

Ответ 1

Управляющая последовательность \xNN вставляет исходный байт NN в строку, тогда как \uNN вставляет байты UTF-8 для кодовой точки Unicode NN в строку UTF-8:

> charToRaw('\xA3')
[1] a3
> charToRaw('\uA3')
[1] c2 a3

Эти два типа escape-последовательности не могут быть смешаны в одной строке:

> '\ua3\xa3'
Error: mixing Unicode and octal/hex escapes in a string is not allowed

Это потому, что escape-последовательности также определяют кодировку строки. Последовательность \uNN явно устанавливает кодировку всей строки в "UTF-8", тогда как \xNN оставляет ее в по умолчанию "неизвестной" (ака. Родной) кодировке:

> Encoding('\xa3')
[1] "unknown"
> Encoding('\ua3')
[1] "UTF-8"

Это становится важным при печати строк, поскольку их необходимо преобразовать в соответствующую выходную кодировку (например, консоль). Строки с определенным кодированием могут быть преобразованы соответствующим образом (см. enc2native), но те, у которых есть "неизвестная" кодировка, просто выводятся как есть:

  • В Linux ваша консоль, вероятно, ожидает текст UTF-8, а поскольку 0xA3 не является допустимой последовательностью UTF-8, она дает вам "".
  • В Windows ваша консоль, вероятно, ожидает текст Windows-1252, а как 0xA3 - правильная кодировка для "£", это то, что вы видите. (Когда строка \uA3, происходит преобразование из UTF-8 в Windows-1252.)

Если кодировка задана явно, соответствующее преобразование будет выполняться в Linux:

> s <- '\xa3'
> Encoding(s) <- 'latin1'
> cat(s)
£

Ответ 2

Взято из Python 2.7 Unicode КАК ДОКУМЕНТЫ:

В исходном коде Python литералы Unicode записываются как строки с префиксом "u" или "U": u'abcdefghijk. Конкретный код точки могут быть записаны с помощью escape-последовательности\u, за которой следует четырьмя шестнадцатеричными цифрами, дающими кодовую точку. Управляющая последовательность \U является аналогично, но ожидает 8 шестнадцатеричных цифр, а не 4.

Литералы Unicode также могут использовать те же escape-последовательности, что и 8-битные строки, включая \x, но\x принимает только две шестнадцатеричные цифры, поэтому он не может выражают произвольную кодовую точку. Октальные экраны могут подниматься до U + 01ff, который является восьмеричным 777.

Проще говоря (надеюсь):
\ 0nn - указывает двузначную восьмеричную escape-последовательность юникода "кодовая точка".
\ xnn - указывает двузначную шестнадцатеричную "кодовую точку" юникода.
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ Unnnnnnnnn - задает восьмеричную шестнадцатеричную "кодовую точку" юникода.

Необходимо использовать полное количество цифр, дополненных ведущими 0.

Например:

>>> ord(u'\010')
8
>>> ord(u'\x10')
16
>>> ord(u'\020')
16
>>> ord(u'\x20')
32
>>> ord(u'\u0020')
32
>>> ord(u'\U00000020')
32
>>> ord(u'\u1000')
4096