Исправьте to_upper() при компиляции boost::locale на OS X с ICU
Компиляция Boost 1.59.0 с использованием настроек по умолчанию в OS X использует библиотеку iconv. При использовании таких вещей, как boost::locale::to_upper()
, с символами UTF8, iconv приводит к таким результатам "GRüßEN”
для таких входов, как "grüßEN”
, Как вы можете видеть, некоторые символы неправильно отображаются в верхнем регистре.
Я прочитал, что исправление заключается в использовании ICU вместо iconv, и поэтому я решил создать Boost с ICU. Метод, который я использую, для моего случая использования следующий:
- Загрузите tar-архив Unix (не ZIP, который имеет окончания строки CR/LF и не будет работать). Распакуйте его.
- Изменить код из файла
boost/libs/filesystem/src/operations.cpp
в строке 1414 читать# if 0
так что резервный код всегда выполняется. В противном случае я получаю сообщение об ошибке, сообщающее, чтоfchmodat
не доступно в OS X 10.9. - Скачать ICU 56.1 на
http://site.icu-project.org/download/56#TOC-ICU4C-Download
, Распакуйте его. - перейдите к ``icu/source```.
- Бежать
./configure --enable-static --disable-shared CXXFLAGS="-std=c++14" --prefix="<path to install ICU>"
- Бежать
gnumake && gnumake install
- кд
boost_1_59_0/
, - Бежать
./bootstrap.sh toolset=darwin macosx-version=10.11 macosx-version-min=10.8 --with-icu=<path where icu was installed>
- Бежать
./b2 toolset=darwin --without-mpi optimization=speed cxxflags="-arch x86_64 -fvisibility=hidden -fvisibility-inlines-hidden -std=c++14 -stdlib=libc++ -ftemplate-depth=512" linkflags="-stdlib=libc++" --reconfigure boost.locale.iconv=off boost.locale.icu=on -sICU_PATH=<path to my icu install dir> -link=static stage
,
Теперь это правильно компилирует версию библиотек Boost, но при использовании этой версии, boost::locale::to_upper()
теперь полностью пропускает символы UTF8 и возвращает "GREN”
для таких входов, как "grüßEN”
,
Тестовый код выглядит так:
static boolean defaultLocaleWasInitialized = false;
...
void String::p_initDefaultLocale(void)
{
boost::locale::generator gen;
std::locale defaultLocale = gen("");
std::locale::global(defaultLocale);
std::wcout.imbue(defaultLocale);
}
...
String::Pointer String::uppperCaseString(void) const
{
if (!defaultLocaleWasInitialized) {
String::p_initDefaultLocale();
defaultLocaleWasInitialized = true;
}
auto result = boost::locale::to_upper(*this);
auto newString = String::stringWith(result.c_str());
return newString;
}
...
TEST(Base_String, UpperCaseString_StringWithLowerCaseCharacters_ReturnsOneWithUpperCaseCharacters)
{
auto test = String::stringWith("Mp3 grüßEN");
auto result = test->uppperCaseString();
ASSERT_STREQ("MP3 GRÜSSEN", result->toUTF8());
}
Любые предложения относительно того, где я иду не так?
1 ответ
AFAIK, это правильное поведение Boost. Boost имеет ограничения в своей локализации, например, он считает ß
одна точка кода и не может прописать ее в верхнем регистре SS
, Следовательно, ваш код не ошибается, это просто проблема с библиотекой Boost: точное поведение некоторых символов UTF8 зависит от платформы.
Увеличение ß
ограничения: функция boost to_upper в string_algo не учитывает локаль, а boost:: attribute::to_upper/to_lower нормально для utf8? boost:: locale не нужен? (особенно комментарии).
Зависимость от платформы: преобразование строк с языковым стандартом Boost: различное поведение в Windows и Linux
Если вы хотите, чтобы он был переведен правильно, вам, вероятно, понадобится другая библиотека. Локализация это сложно!