【问题标题】:Correct to_upper() when compiling boost::locale on OS X with ICU在带有 ICU 的 OS X 上编译 boost::locale 时更正 to_upper()
【发布时间】:2016-02-10 19:10:36
【问题描述】:

在 OS X 上使用默认设置编译 Boost 1.59.0 使用 iconv 库。当使用像 boost::locale::to_upper() 这样的带有 UTF8 字符的东西时,iconv 会导致像"GRüßEN” 这样的输入结果像"grüßEN” 这样的输入。如您所见,某些字符的大写字母不正确。

我读到修复是使用 ICU 而不是 iconv,所以我开始使用 ICU 构建 Boost。对于我的用例,我遵循的方法如下:

  1. 下载 unix tar 球(不是 ZIP,它具有 CR/LF 行结尾并且不起作用)。解压它。
  2. 将文件boost/libs/filesystem/src/operations.cpp 的第1414 行的代码修改为读取# if 0,以便始终执行回退代码。否则我会收到一个链接错误,告诉您fchmodat 在 OS X 10.9 中不可用。
  3. http://site.icu-project.org/download/56#TOC-ICU4C-Download 下载ICU 56.1。解压它。
  4. cd 到 ``icu/source```。
  5. 运行./configure --enable-static --disable-shared CXXFLAGS="-std=c++14" --prefix="<path to install ICU>"
  6. 运行gnumake && gnumake install
  7. cd 到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());
}

关于我哪里出错了有什么建议吗?

【问题讨论】:

  • iconv 在不同编码之间转换字符串——它不会进行大小写转换。您应该包含一个显示问题的小型测试程序的代码。
  • 将代码添加到我的问题中。试图找到我在哪里读到 ICU 是正确转换所必需的。字符串是否使用您的 boost 库正确转换?
  • 在字符串文字中包含非 ascii 字符,例如在 "Mp3 grüßEN" 中是未定义的行为。您必须以其他方式确保您的字符串包含您希望它包含的字符,例如。通过 UTF-8 对该字符串进行编码并将生成的字节编码如下:ü"\xc3\xbc"。您使用的任何库都必须以某种方式知道您使用的编码。
  • 使用-DU_CHARSET_IS_UTF8=1重新编译ICU。使用字符串文字 "GR \xC3\xBC en" 作为测试时,我得到相同的结果(跳过的字符)。
  • 我不确定输入是否是问题所在。如果我复制取自stackoverflow.com/questions/22331487/… 的代码,我会得到grüßen vs GREN gren gren

标签: macos boost unicode locale icu


【解决方案1】:

AFAIK,这是正确的 Boost 行为。 Boost 在其本地化方面存在局限性,例如,它将ß 视为单个代码点并且不能将其大写为SS。因此,您的代码不会出错,这只是 Boost 库的问题:某些 UTF8 字符的确切行为取决于平台。

Boost ß 限制:boost to_upper function of string_algo doesn't take into account the localeboost::algorithm::to_upper/to_lower ok for utf8? boost::locale not necessary?(尤其是 cmets)。

平台依赖:string conversion with boost locale: different behaviour on windows and linux

如果您希望它被正确翻译,您可能需要另一个库。本地化很难!

【讨论】:

  • 对于没有 ICU 的 boost::locale 可能是正确的,但 ICU 的行为不依赖于平台,我的理解是 boost 在 ICU 中的行为不依赖于平台。 boot::locale 自己的文档提到支持大写 ß 的行为 boost.org/doc/libs/1_48_0/libs/locale/doc/html/conversions.html 无论如何,可以肯定地说忽略字符(如我所见)不是正确的行为,所以我的问题仍然存在,我要去哪里从头开始编译这些库是错误的。
猜你喜欢
  • 2014-07-02
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-04
  • 2012-05-01
  • 2011-11-03
相关资源
最近更新 更多