D Строковые литералы Unicode: невозможно напечатать определенный символ Unicode

Я просто пытаюсь подобрать D, пришедший из С++. Я уверен, что это что-то очень простое, но я не могу найти никакой документации, которая могла бы мне помочь. Я пытаюсь напечатать символ à, то есть U+00E0. Я пытаюсь присвоить этот символ переменной, а затем использовать write() для вывода его на консоль.

этот веб-сайт сообщает мне, что U+00E0 кодируется как 0xC3 0xA0 в UTF-8, 0x00E0 в UTF-16 и 0x000000E0 в UTF-32.

Обратите внимание, что для всего, что я пробовал, я пытался заменить string на char[] и wstring на wchar[]. Я также пробовал с суффиксами w или d после широких строк и без них.

Эти методы возвращают ошибку компилятора «Недопустимый завершающий код»:

string str = "à";
wstring str = "à"w;
dstring str = "à"d;

Эти методы печатают совершенно другой символ (Ò U+00D2):

string str = "\xE0";
string str = hexString!"E0";

И все эти методы выводят что-то вроде ˧á (обратите внимание, á ≠ à!), то есть UTF-16 0x2E7 0x00E1:

string str = "\xC3\xA0";
wstring str = "\u00E0"w;
dstring str = "\U000000E0"d;

Любые идеи?


person Joe C    schedule 23.11.2018    source источник
comment
В какой кодировке вы сохраняете исходный файл и в какой кодировке установлен ваш выходной терминал? А какая у вас операционная система? Сам язык определяет эти вещи, но чтение из исходного кода и запись на экран могут привести к недопониманию.   -  person Adam D. Ruppe    schedule 23.11.2018
comment
Самый нижний результат выглядит так, как будто кодировка IBM437.   -  person Mr Lister    schedule 23.11.2018
comment
Спасибо за ответ! У меня 64-битная Windows 10.0.17134. Попытка найти или изменить кодировку исходного файла в Code::Blocks немного непонятна. Кажется, ранее он был закодирован в кодировке WINDOWS, но теперь я переключил его на UTF-32LE, воссоздал проект, и проблемы продолжаются. Я считаю вполне вероятным, что проблема заключается только в записи на консоль, но это важно для моих нужд. Кажется, есть решение для C (docs.microsoft.com/en-us /windows/console/setconsoleoutputcp) — есть ли эквивалент D?   -  person Joe C    schedule 24.11.2018
comment
Вы хотите, чтобы источник был закодирован как UTF-8. Компилятор D немного придирчив к этому. Хотя, если вы не можете этого сделать, вы также можете придерживаться ASCII в исходном коде и использовать escape-последовательности \uxxxx для записи других символов. Для вывода та же функция является ответом: помните, D может вызывать функции C так же, как C. Так что да, SetConsoleOutputCP(65001) перед выполнением вывода должно работать. Вы можете import core.sys.windows.windows; сделать эту функцию определенной.   -  person Adam D. Ruppe    schedule 25.11.2018


Ответы (2)


Я подтвердил, что это работает на моем компьютере с Windows, поэтому сейчас напечатаю это как ответ.

В исходном коде, если вы копируете/вставляете символы напрямую, убедитесь, что ваш редактор сохраняет их в кодировке utf8. Компилятор D настаивает на этом, поэтому, если он выдает ошибку компиляции по поводу utf, возможно, поэтому. Я никогда не использовал c: b, но в старом ответе в Интернете говорилось, что edit-> encodings ... это настройка где-то в редакторе, несмотря ни на что.

Или вы можете заменить символы в исходном коде на \uxxxx в строках. НЕ используйте шестнадцатеричную строку, то есть для двоичных байтов, но ваш пример "\u00E0" хорош и будет работать для любого типа строки (а не только wstring, как в вашем примере).

Затем, на стороне вывода, это зависит от вашей цели, потому что программа просто выводит байты, и программа-получатель должна интерпретировать ее правильно. Поскольку вы сказали, что работаете в Windows, ключевым моментом является установка кодовой страницы консоли на utf-8, чтобы она знала, что вы пытаетесь сделать. Действительно, ту же функцию C можно вызвать и из D. Ведущие к этой программе:

import core.sys.windows.windows;
import std.stdio;

void main() {
    SetConsoleOutputCP(65001);
    writeln("Hi \u00E0");
}

распечатать успешно. В более старых версиях Windows вам может потребоваться изменить шрифт, чтобы увидеть символ (в отличие от общего поля, которое оно показывает, потому что некоторые шрифты не содержат всех символов), но в моем окне Windows 10 он просто работал с шрифт по умолчанию.

Кстати, технически кодовая страница консоли является общей настройкой (после запуска программы и ее выхода вы все равно можете нажать свойства в окне консоли и увидеть отраженное там изменение), и вам, возможно, следует установить ее обратно при выходе из вашей программы. Вы можете получить это при запуске с помощью функции get ( https://docs.microsoft.com/en-us/windows/console/getconsoleoutputcp ), сохраните его в локальной переменной и установите обратно при выходе. Вы могли бы auto ccp = GetConsoleOutputCP(); SetConsoleOutputCP(65005;) scope(exit) SetConsoleOutputCP(ccp); прямо при запуске - выход из области видимости будет запущен при выходе из функции, поэтому делать это в основном было бы довольно удобно. Просто добавьте проверку ошибок, если хотите.

В документах Microsoft ничего не говорится об установке обратно, так что это, вероятно, не имеет значения, но все же я хочу упомянуть об этом на всякий случай. Но также знание того, что он является общим и сохраняется, может помочь в отладке - если он работает после того, как вы его прокомментируете, это не потому, что код не нужен, а просто потому, что он был установлен ранее и еще не отменен!

Обратите внимание, что запуск его из IDE может быть не совсем таким же, потому что IDE часто направляют вывод вместо того, чтобы запускать его прямо на консоль Windows. Если это произойдет, дайте мне знать, и мы можем напечатать кое-что об этом для будущих читателей. Но вы также можете открыть свою собственную копию консоли (запустить программу вне IDE), и она должна отображаться правильно для вас.

person Adam D. Ruppe    schedule 25.11.2018
comment
Блестяще, работает шарм! Просто отметим, что кодировка UFT-8 \xC3\xA0 работает так же хорошо, как à, который является тем же символом в UTF-16. - person Joe C; 26.11.2018
comment
Правильно, вы можете делать это байт за байтом, но компилятор будет переводить различные кодовые точки (строго говоря, \uxxxx не utf-16, это номер кодовой точки Unicode) в правильную кодировку для данной строки. Таким образом, использование материала \u создаст правильные байты utf-8 в этом контексте или байты utf-16 в этом контексте и т. д. - person Adam D. Ruppe; 26.11.2018

Исходный код D должен быть закодирован как UTF-8. Я предполагаю, что вы помещаете символ UTF-16 в исходный файл UTF-8.

E.g.

import std.stdio;
void main() {
    writeln(cast(char)0xC3, cast(char)0xA0);
}

Выведет как UTF-8 символ, который вы ищете.

Что вы можете затем жестко закодировать так:

import std.stdio;
void main() {
    string str = "à";
    writeln(str);
}
person Richard Andrew Cattermole    schedule 23.11.2018
comment
Спасибо за попытку, но, к сожалению, у них те же проблемы, что и у методов, которые я уже пробовал... - person Joe C; 24.11.2018