Использование спецификатора boost::format %s со строками UTF-8
Мы добавляем поддержку UTF8 в существующее приложение с большой базой кода. Это приложение использует boost::format()
и вывод в не-ASCII символах не выравнивается должным образом. В частности, при использовании %{width}.{length}
спецификатор, boost::format()
считает символы, которые не "делают правильные вещи" со строками utf8. Я думаю, что должно быть возможно изменить код длины строки (который, вероятно, string::size()
) использовать utf8len()
или что-то аналогичное, основанное на... что-то?
В этом случае нецелесообразно изменять существующую кодовую базу для использования UCS2 (или UCS4, или UTF-16 и т. Д.), Но можно изменить boost::format()
если необходимо. Я надеялся, что кто-то еще столкнулся с этой потребностью, и может указать мне на возможное решение.
Примечание: я нашел несколько веб-страниц об использовании локалей с utf8, но большая часть этого показалась более подходящей для преобразования в / из utf8 и UCS4 в потоках.
1 ответ
AFAIK Boost Format измеряет все в единицах кода, даже если используется локаль на основе UTF-8.
Если вы можете переключиться на другую библиотеку, рассмотрите C++20 std::format
или библиотека форматирования {fmt}, которая считает ширину в единицах ширины отображения (аналогично wcswidth), чтобы выравнивание было правильным. Например
fmt:: print ("┌ {0: ─ ^{2}}┐\ n" "│{1: ^{2}}│\ n" "└{0: ─ ^{2}}┘\ n", "", "Привет, мир!", 20);
печатает:
┌────────────────────┐
│ Hello, world! │
└────────────────────┘
Отказ от ответственности: я являюсь автором {fmt} и C++20 std::format
Возможно, это слишком поздно для вас, но, возможно, это поможет кому-то еще. Boost::format принимает std:: locale в качестве необязательного параметра шаблона. (см. http://www.boost.org/doc/libs/1_55_0/libs/format/doc/format.html). Если вы передадите ему локаль с поддержкой юникода, такую как boost::locale("en_US.UTF-8"), вы должны получить желаемое поведение.
Вместо того, чтобы каждый раз передавать языковой стандарт конструктору boost:: format, вы также можете установить языковой стандарт вашего приложения по умолчанию, что может помочь вам избежать других проблем. Если вы выберете этот путь, я бы порекомендовал использовать boost:: locale вместо std:: locale, так как boost:: locale не изменит ваше числовое форматирование, если вы не попросите его об этом (документы здесь).
В общем, это подход goto для того, чтобы приложение на C++ хорошо работало с Unicode. Если функциональность может использовать локаль (std::regex, std::sort, boost::format), предоставьте ей локаль, поддерживающую юникод, и вы должны быть в безопасности (а если нет, пожалуйста, скажите мне, я хочу знать).
Если вы создаете небольшое и легкое приложение и заботитесь только о 80% -ом случае, вы можете не захотеть платить цену за включение ICU (Internation Components for Unicode), который является языковым стандартом для усиления двигателя по умолчанию, когда предоставляется поддержка unicde. В этом случае соберите Boos, используя поддержку Unicode вашей ОС или Posix, и ваше приложение останется небольшим и легким, но у вас не будет большой поддержки Unicode, например, нескольких уровней сортировки.
Для описываемой проблемы поддержки Posix вполне достаточно.