UnicodeString со строковыми литералами и шестнадцатеричными значениями

Есть ли какая-либо мыслимая причина, по которой я увижу разные результаты, используя строковые литералы Unicode, по сравнению с фактическим шестнадцатеричным значением для UChar.

UnicodeString s1(0x0040); // @ sign
UnicodeString s2("\u0040");

s1 не эквивалентен s2. Почему?


person Ternary    schedule 15.11.2011    source источник
comment
Что такое UnicodeString -- определено ли оно отделением интенсивной терапии?   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB UnicodeString — это ICU.   -  person moshbear    schedule 16.11.2011
comment
@moshbear: у вас есть ссылка на справку по API? Это должно быть прямолинейно, чтобы разобраться.   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB icu-project.org/apiref/icu4c/classUnicodeString.html   -  person moshbear    schedule 16.11.2011
comment
Хм, литерал "\u0040" просто не определен четко (то есть он определяется реализацией). Так что я думаю, что мы не можем ответить на это в целом. Если бы это была строка UTF-8 (u8"\u0040"), мы могли бы быть в лучшей форме.   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB Под реализацией вы подразумеваете компилятор или рассматриваемую библиотеку (в данном случае ICU)?   -  person Ternary    schedule 16.11.2011
comment
@Ternary: я предполагаю, что что-то вроде набора символов выполнения компилятора сыграет роль. Хорошие компиляторы позволяют настроить это. В любом случае вам просто не следует использовать escape-последовательности \u и \U в этом контексте. Вот мой предыдущий пост на эту тему.   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB Ради разговора, что, если значение \u было прочитано из файла во время выполнения? Итак, если у вас есть @ в файле, который во время выполнения считывается в UnicodeString, как это меняет поведение? Потому что результаты разные, но я не уверен, почему.   -  person Ternary    schedule 16.11.2011
comment
@Ternary: это не имеет смысла. \u – это экранирующая последовательность, представляющая собой лексическую особенность грамматики C++, используемую для литеральных значений. Вы не можете прочитать его из файла. (Де)сериализация всегда требует документирования формата.   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB Что ж, используя связку ICU, вы можете иметь файлы ресурсов, которые представляют собой пары ключ-значение в формате keyname {"some text \u0040"}, и точно отображать текст для ключа в UnicodeString.   -  person Ternary    schedule 16.11.2011
comment
@Ternary: это все еще не имеет смысла. Если вы читаете его из файла, это просто данные, и, возможно, ICU поставляется с парсером для этого. Но это не то же самое, что литерал управляющей последовательности в исходном коде. Это все равно, что сказать, что если вы читаете строку "terminate()", ваша программа останавливается...   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB Но ctor UnicodeString просто берет char * (я полагаю), который готов посимвольно из файла (я полагаю), или, может быть, вы правы, и у ICU есть парсер для этого. Я говорю, что это действительно работает. Еще одна точка данных в вопросе, который меня озадачивает.   -  person Ternary    schedule 16.11.2011
comment
@Ternary: между UnicodeString("\u0040") и UnicodeString("\\u0040") есть принципиальная разница!   -  person Kerrek SB    schedule 16.11.2011
comment
Я это понимаю. Я просто говорю, что ICU поддерживает @ в качестве значения в пакете ресурсов userguide.icu-project. org/locale/resources   -  person Ternary    schedule 16.11.2011
comment
@KerrekSB Похоже, это делается ICU во время выполнения Since ICU is not a compiler extension, the "unescaping" is done at runtime and the backslash itself must be escaped (duplicated) so that the compiler does not attempt to "unescape" the sequence itself. Из userguide.icu-project.org/strings< /а>   -  person Ternary    schedule 16.11.2011
comment
@Ternary: и пенни падает :-)   -  person Kerrek SB    schedule 16.11.2011
comment
@KerrekSB Бинго. Я нашел причину, почему в их doc. Большое спасибо за вашу помощь и время.   -  person Ternary    schedule 16.11.2011


Ответы (4)


Управляющая последовательность \u AFAIK определяется реализацией, поэтому трудно сказать, почему они не эквивалентны, не зная подробностей о вашем конкретном компиляторе. Тем не менее, это просто небезопасный способ ведения дел.

UnicodeString имеет конструктор, принимающий UChar и один для UChar32. Я был бы явным при их использовании:

UnicodeString s(static_cast<UChar>(0x0040));

UnicodeString также предоставляет довольно удобный метод unescape():

UnicodeString s = UNICODE_STRING_SIMPLE("\\u4ECA\\u65E5\\u306F").unescape(); // 今日は
person NuSkooler    schedule 20.06.2012

не удалось воспроизвести на ICU 4.8.1.1

#include <stdio.h>
#include "unicode/unistr.h"

int main(int argc, const char *argv[]) {
  UnicodeString s1(0x0040); // @ sign
  UnicodeString s2("\u0040");
  printf("s1==s2: %s\n", (s1==s2)?"T":"F");
  //  printf("s1.equals s2: %d\n", s1.equals(s2));
  printf("s1.length: %d  s2.length: %d\n", s1.length(), s2.length());
  printf("s1.charAt(0)=U+%04X s2.charAt(0)=U+%04X\n", s1.charAt(0), s2.charAt(0));
  return 0;
}

=>

s1==s2: T

s1.длина: 1 s2.длина: 1

s1.charAt(0)=U+0040 s2.charAt(0)=U+0040

gcc 4.4.5 RHEL 6.1 x86_64

person Steven R. Loomis    schedule 16.11.2011

Для всех, кто нашел это, вот что я нашел (в документации ICU).

Кодировки кодовых страниц компилятора и набора символов времени выполнения не указаны стандартами языка C/C++ и обычно не являются формой кодировки Unicode. Обычно они зависят от настроек отдельной системы, процесса или потока. Следовательно, невозможно создать экземпляр символа Юникода или строковой переменной непосредственно с помощью символьных или строковых литералов C/C++. Единственный безопасный способ — использовать числовые значения. Это не проблема для строк пользовательского интерфейса (UI), которые переведены.

[1] http://userguide.icu-project.org/strings

person Ternary    schedule 16.11.2011
comment
на некоторых платформах вы можете сделать L...., чтобы получить строку юникода. Но, как говорится, не указано. - person Steven R. Loomis; 17.11.2011

Проблема заключается в двойных кавычках в вашей константе \u. Это правильно оценено:

wchar_t m1( 0x0040 );
wchar_t m2( '\u0040' );
bool equal = ( m1 == m2 );

equal было true.

person Gnawme    schedule 16.11.2011
comment
Я не могу найти ничего в стандарте С++ 11, подтверждающего это. У вас есть ссылка? - person Kerrek SB; 16.11.2011
comment
@KerrekSB: Если вы спрашиваете о зарезервированной области, я полагаю, что это относится к отделению интенсивной терапии (с которым я едва знаком). - person Gnawme; 16.11.2011
comment
Я собираюсь понизить это. Я не думаю, что это относится к вопросу. Кроме того, символьный псевдолитерал '\u0040' определен не лучше, чем строковый псевдолитерал "\u0040"; оба зависят от реализации и контекста и вообще не должны использоваться таким образом. - person Kerrek SB; 16.11.2011
comment
@KerrekSB: Стандарт C++03, раздел 2.2, Наборы символов: конструкция universal-character-name предоставляет способ называть другие символы. [например. \u hex-quad или \u hex-quad hex-quad]. Символ, обозначенный универсальным именем символа \uNNNN, представляет собой символ, короткое имя которого в ISO/IEC 10646 равно 0000NNNN. Каким образом вы имеете в виду «зависимость от реализации»? - person Gnawme; 16.11.2011
comment
Я знаю, что означает \uXXXX. Проблема в том, что означает '\uXXXX'? Видите ли, первое — просто абстрактное значение, а второе — значение конкретного типа. И нет универсального правила, как произвольная кодовая точка Unicode должна превратиться в char (что является типом литерала ''). Сравните это, скажем, с U"\uXXXX", где строка состоит из char32_t, а семантика стандартизирована (поэтому строка состоит из двух элементов, первый — 32-битное целое число 0x0000XXXX, а второй — ноль). - person Kerrek SB; 16.11.2011
comment
В ICU '\u0040' указывает символ '@', используя допустимую экранирующую последовательность универсального имени-символа. - person Gnawme; 16.11.2011
comment
'@' будет символьным значением, которое представляет U+0040 в любой кодировке, используемой для char, если эта кодировка может представлять U+0040, а если нет, то значение определяется реализацией. Поэтому, если вы хотите представить U + 0040 в системной кодировке символов, тогда '\ u0040' - правильный способ сделать это. - person bames53; 16.11.2011