Исправьте 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. Метод, который я использую, для моего случая использования следующий:

  1. Загрузите tar-архив Unix (не ZIP, который имеет окончания строки CR/LF и не будет работать). Распакуйте его.
  2. Изменить код из файла boost/libs/filesystem/src/operations.cpp в строке 1414 читать # if 0 так что резервный код всегда выполняется. В противном случае я получаю сообщение об ошибке, сообщающее, что fchmodat не доступно в OS X 10.9.
  3. Скачать ICU 56.1 на http://site.icu-project.org/download/56#TOC-ICU4C-Download, Распакуйте его.
  4. перейдите к ``icu/source```.
  5. Бежать ./configure --enable-static --disable-shared CXXFLAGS="-std=c++14" --prefix="<path to install ICU>"
  6. Бежать gnumake && gnumake install
  7. кд boost_1_59_0/,
  8. Бежать ./bootstrap.sh toolset=darwin macosx-version=10.11 macosx-version-min=10.8 --with-icu=<path where icu was installed>
  9. Бежать ./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

Если вы хотите, чтобы он был переведен правильно, вам, вероятно, понадобится другая библиотека. Локализация это сложно!

Другие вопросы по тегам