Pull to refresh

Comments 61

Вы за русскоязычные комментарии?
Вообще, конечно же за англоязычные.
В редких случаях приходится писать русскоязычные (для отдельных «личностей»). В данном случае — это лишь пример к статье на русском языке.
Спасибо :-) Интересный материал.
Поясните, а в каких случаях вам вообще может потребоваться указывать юникодные константы в тексте программы?

Частенько.
Совсем недавно писали разборщик полуструктурированных файлов на русском языке (cp1251, cp866, utf-8) для наполнения по ним базы данных. Самым простым вариантом реализации были регулярки. В этом проекте меня и удивила команда своими подходами к работе с различными кодировками и обращение с xpressive.
Логично, спасибо. Правда, тут же возникает второй логичный вопрос: чем обусловлено решение такой задачи на C++?
Количество файлов ~300 000. Ежедневно поступает ~100-200. Да и команда больше знакома с крестами…
Разбор математических или химических формул.
По-моему, в русскоязычных комментариях нет ничего плохого. Если, конечно, это не иностранная айти-фирма с англоязычными программистами.
С доводом согласен. Зачастую — это достаточный аргумент.
Никогда не знаешь, что случится с кодом через несколько лет. Вдруг вы этот код отдадите поддерживать и/или развивать на аутсорс в Индию или Китай?
В Индию или Китай? Я — точно нет. Такова специфика. У других, допускаю, иначе.
что плохого в русскоязычных комментариях?
Выше уже рассказали :-) Open source.
От себя могу добавить, что это позволяет избежать лишних разговоров с людьми, которым в этом коде явно не стоит копаться.
Да и в конце концов, зачем переключать раскладку? Это уменьшает скорость печати :-)
UTF-8 с BOM — это нелепая выдумка Microsoft, потому что Byte Order Mark не имеет никакого смысла для UTF8.
MS Visual Studio прекрасно отображает UTF8 файлы без этой метки, а использовать строчные литералы в не ASCII кодировке я считаю дурной практикой.
Отображает — да, отлично. А попробуйте скомпилировать вот это в файле UTF-8 без BOM и с BOM:
  1.  
  2. std::wstring wstr=L"АБВГ";
  3. std::cout << (wstr[0] == 0x0410 ? "ok" : "fail" );
  4.  


>а использовать строчные литералы в не ASCII кодировке я считаю дурной практикой
Я уже говорил, что порой это необходимость. Если использовать юникодные константы получаются таки крокодилы в коде, в которых потом очень сложно разобраться. Последний пример — анализ текстов.
GCC 4.4.3 совершенно пофигу, есть в UTF-8-файле BOM или нет. В обоих случаях вывод совершенно идентичный, такой:
merlin@merlin-hpmini ~/asdf $ cat test.cpp
#include main() {

std::wstring wstr=L«АБВГ»;
std::cout << (wstr[0] == 0x0410? «ok»: «fail» );

}
merlin@merlin-hpmini ~/asdf $ g++ test.cpp -o test
merlin@merlin-hpmini ~/asdf $ ./test
ok
Вообще, BOM имеет смысл для всех юникодных кодировок, кроме UTF-8. В этой кодировке уже жестко зафиксирован порядок байтов, он не зависит ни от каких маркеров и соответственно в них нет никакого смысла.

Более того, отдельным программам становится плохо от этих маркеров. В примере выше cat и g++ просто не заметили его, как будто его и нет.
(простите, блокквоту забыл закрыть)
Добавлю, что просто скомпилированные файлы отличаются в размере на два байта. Если выполнить strip test для каждого варианта, то они становятся идентичными.
gcc — да, пофигу
Речь шла о msvc. И тут дело не в том, что он порядок байт путает…
Он что же, саму кодировку по BOMу опознаёт?
Ну почти…
Википедия пишет:
While Unicode standard allows BOM in UTF-8 [2], it does not require or recommend it[3]. Byte order has no meaning in UTF-8[4] so a BOM only serves to identify a text stream or file as UTF-8 or that it was converted from another format that has a BOM.

BOM помогает понять msvc, что файл в UTF-8 и правильно интерпретировать L«АБВГ» как 4 символа wchar_t, а не 8 символов char.
кажись gcc работает в текущей локали, то есть вы написали L«АБВГ» в текущей локали, gcc и распознал это в текущей локали.
Попробуйте написать автоматическое определения кодировки. Для определения файлов в UTF8 без BOM требуется немало кода(к примеру можно глянуть код Notepad++), мне кажется всетаки смысл в нем есть.
толку? все равно код определения кодировки придется писать, потому что не все файлы имеют bom
Хотя бы если BOM есть очень быстро кодировка определится. Надо было сделать BOM обязательным, тогда бы не у кого проблем не было.
Это если текущая локаль пользователя на платформе обеспечивает нужное преобразование (нужные фасеты имеются в локале пользователя). В противном случае получите белиберду или исключение.
Я считаю, что нет достаточно жестокого наказания для тех людей, которые сегодня начинают писать новый софт, используя cp125*
К сожалению, до сих пор используются эмуляторы терминалов и файловые системы, использующие национальные однобайтовые кодировки по-умолчанию.
С терминалами можно бороться перекодированием, а что за файловые системы вы имели в виду?
FAT, например. Знаете, такая файлуха, в которую обычно форматируют флешки.
FAT не умеет юникодные имена только в случае 8.3

Но все винды начиная с 95 OSR 2 и NT 4.0 умеют длинные имена, которые хранятся именно в юникоде… Так что поясните, о каких именно проблемах с юникодом в фате речь?
Не знаю насчёт виндов, но у PSP мне флешку отформатила так, что монтировать её надо, указывая кодировкой cp1251. Гнум c KDE сами с определением справляется, но факт остаётся фактом.
Вот уж не знаю, где вы такой PSP взяли, у меня нормально форматирует. И на FAT никогда не использовалась cp1251. может в этом проблема?
Не знаю, может, прошивка такая, но при монтировании без параметров вижу кракозябры
Если у вас локаль cp1251, то надо указать iocharset=cp1251, mount сам не догадается.
Если они сидят под виндой, то можно просто выставить им дефолтной кодировкой для неюникодных программ, скажем, иврит или грузинский (любой язык с алфавитом не из латиницы и не из кириллицы) и отобрать права на изменение настроек локали. Через пару дней они станут true-юникодерами :)

Ох и натерпелся я от таких горе-программистов, но зато перешёл на правильный софт, который не страдает старыми кодировками.
> Если кто не знает, в vim BOM можно добавить к файлу с помощью команды «set bomb».
Сильно улыбнуло :)
Э-э-э,

unicyr_ctype.hpp, line 189

std::map<mask, wchar_t> masks;

а не наоборот ли?

p.s. пардон, если что, очень спать хочется :)

Да, похоже вы правы, спасибо — закоммитил.
А спать действительно хочется =)
Спасибо за статью.
Теперь я лучше понимаю, что дала миру языков программирования Java.
Простите, вплотную с Java не работал, но там чтение файлов в различных кодировках или получение данных из какого-либо потока в разных кодировках делается ява-машиной?
В принципе, если хорошо почитать доки перед тем, как начинать работу с потоками, то все ОК.
Но вывод в виндовую консоль по-прежнему — нетривиальная задача. Хотя в JSE6 класс Console сииильно облегчил задачу.
Тогда я не понял фразу товарища OnoIt… Что такого Java дала миру языков программирования в обсуждаемой области?!
ИМХО для меня главное — там есть только ОДИН ТИП СТРОКИ.
И все конверсии данных «извне» проходят довольно незаметно, если, конечно, использовать предназначенные для этого классы (это к заметке об чтении документации, а то такие велосипеды встечал — о-го-го! Гослинг плачет кровавыми слезами)
Надо задавать кодировку для ввода-вывода, ява-машина прозрачно преобразует из внешней кодировки в UNICODE и обратно ( посмотрите InputStreamReader/OutputStreamWriter объекты )

Тип String имеет UNICODE кодировку по умолчанию, можно создать строку с другой кодировкой, или преобразовать массив байтов в строку в соответствии с кодировкой.

Отвечу и по другим темам статьи.

При компиляции кодировка исходников также задается ключом компилятора. Имена переменных и пр. можно писать в UNICODE — но с этим надо быть осторожным, мы пишем все на английском, а комментарии можно и на русском.

Regex объекты знают про UNICODE.

Locale объект позволяет задавать дату, время, числа с разделителями в формате для определенного языка, страны — удобно.

Ошибся — строки всегда в UNICODE ( «A String represents a string in the UTF-16 format» ), а конструктор строки может принимать байтовый массив и название кодировки.
Не знаю, как обстоят дела на данный момент, но лет пять назад на всех ява-форумах была ветка (и не одна), как заставить яву понимать кириллицу :) А в русскоязычных книгах по яве была специальная сноска, что, дескать, юникод юникодом, но для поддержки кириллицы есть специальный бубен :)
более логично перейти на расширенные символы wchar_t и использовать UCS-2.

Если так хочется двухбайтный wchar_t, то лучше использовать UTF-16. UCS-2 устарел.
Я, похоже, не до конца разобрался в вопросе. Не знаю точно с чем конкретно работают современные компиляторы. Наверное UTF-16…
Из unicode.org:
UTF-16 and UCS-2 are identical for purposes of data exchange. Both are 16-bit, and have exactly the same code unit representation.
www.unicode.org/faq/basic_q.html#14
В обмене данных они одинаковые, в обработке UTF-16 подразумевает, например, поддержку суррогатных пар. В UCS-2 подразумевается, что за пределами BMP юникода нет.
IMHO, современные компиляторы используют UCS2. Потому что он намного удобней в работе, 2 байта всегда ровно один символ.
Все стандартные функции поддерживающие wchar_t расчитаны на работу сUCS2 строками
>Потому что он намного удобней в работе, 2 байта всегда ровно один символ.
На самом деле, удобнее всего ASCII. Один байт всегда ровно один символ, да ещё и старший бит можно использовать как угодно.
>Все стандартные функции поддерживающие wchar_t расчитаны на работу сUCS2 строками
Не знаю, как в win (которая вроде бы после Win2000 переходила на UTF-16), но в *nix под wchar_t обычно понимают UCS-4. И вообще, рассчитывать на конкретный размер wchar_t — моветон.
Да в gcc и vc отличаются размеры wchar_t, но не в том смысл. Смысл в том что в UCS один символ всегда sizeof(wchar_t) байт и это удобно. думаю даже в gcc стандартные строковые функции рассчитаны что wchar_t* это UCS строка.
>даже в gcc стандартные строковые функции рассчитаны что wchar_t* это UCS строка.
В gcc все функции рассчитаны на то, что wchar_t* — это UCS-4 строка. А в ней суррогатные пары не нужны. Конечно, даже это не освобождает от комбинирующих и null-width символов.
>и это удобно
А я о чём? Удобно использовать char для хранения строк, а с включенным старшим битом — для escape и прочих личных целей. Правда, дикари из одной северной страны после этого возникают с « Е ПРОМЕ ЯЕМ БУКВУ    А ПОГА ЫЙ ПРОБЕЛ» и багрепортят о проблемах с буквой «я», но нам какое дело?
Там не то написано, там перечисленно какие компоненты поддерживают UTF16 в Windows.

Посмотрите к примеру реализацию std::wstring или wcslen.
Потрясение устоями! ostreambuf_iterator можно не разыменовывать, у него перегружен оператор =!
Sign up to leave a comment.

Articles