【问题标题】:c++ towupper() doesn't convert certain charactersc++ towupper() 不转换某些字符
【发布时间】:2017-05-23 03:58:30
【问题描述】:

我使用 Borland C++ Builder 2009,我的应用程序被翻译成多种语言,包括波兰语。

对于一小部分功能,我使用 towuppper() 将字符串大写,以便在用户第一次忽略时强调它。

原始字符串从语言 dll 加载到 utf16 wstring 对象中,我这样转换:

int length = mystring.length() ;
for (int x = 0 ; x < length ; x++)
    {
    mystring[x] = towupper(mystring[x]);
    }

除波兰语外,所有这些都运行良好,以下句子:“Rozumiem ryzykowność wykonania tejoperacji”转换为“ROZUMIEM RYZYKOWNOść WYKONANIA TEJ OPERACJI”而不是“ROZUMIEM RYZYKOWNOŚĆ WYKONANIA TEJ OPERACJI"

(请注意单词“ryzykowność”的最后两个字符不会转换)。

似乎没有此字符的大写 Unicode 变体可用。 Unicode 字符 346 可以解决问题。 http://www.fileformat.info/info/unicode/char/015a/index.htm

这是我过时的编译器安装中的过时库的问题,还是我遗漏了其他东西?

【问题讨论】:

  • 这些字符是规范化的,还是由多个组合代码单元组成?
  • 它不应该是一个过时的库,因为 śŚ 都存在于 Unicode v.1.1,日期为 1993 年。如果是,则此函数的创建者有错误。
  • 您的 C 语言环境设置为什么? “如果当前 C 语言环境中没有列出大写版本,则 ch 的大写版本或未修改的 ch。” 你在 unicode 语言环境中吗? std::setlocale(LC_ALL, "en_US.utf8");?来自en.cppreference.com/w/cpp/string/wide/towupper 一些易于阅读的关于通过 google 找到的函数的文档。如果这不能解决问题,请提供minimal reproducible example
  • 现在为什么要使用 Borland?
  • @nikau6:好吧,为什么不呢? CBuilder 有自己的与 Windows 接口的版本,但对于其余部分,它只是另一个 C++ IDE。

标签: c++ c++builder unicode-string


【解决方案1】:

C++ 标准不要求实现towupper 来执行Unicode 大小写转换。即使宽字符串是 Unicode 字符串。即使在一个小写代码点映射到一个大写代码点的情况下。

此外,towupper 无法执行正确的 Unicode 大小写转换,即使实现支持它也是如此。大小写转换实际上可以更改 Unicode 字符序列中代码点的数量。而towupper 无法做到这一点。

不能依赖 C++ 标准库来处理此类 Unicode 问题。您需要迁移到 ICU 等专用 Unicode 库。

【讨论】:

  • @M.M:即使一个实现提供了宽字符函数尝试尽可能多地实现 Unicode,它仍然是一个无法兑现的承诺。不可靠的功能是不可靠的。如果你需要 Unicode 来工作,那么你需要它来实际工作,除非它不工作,否则大部分情况下都不能工作。
  • @NicolBolas 这一切都取决于问题域。如果您知道您将使用所有可能语言的有限子集,那么了解一种简单的方法是否适用于这些特定语言会很有用。
  • @MarkRansom:问题域发生了变化。从英语到西班牙语/法语是一个艰难的跳跃;你需要打破 ASCII 编码。但是,假设您可以访问支持 Unicode 的库,那么从英语到 Unicode 的跳跃同样困难。从有限的后 ASCII 跳转到 Unicode 也需要大量工作(例如,大小写转换不再是字符到字符,而是字符串到字符串)。最好在第一次就正确完成所有工作,这样当你的老板说你需要德国人的支持(towupper 失败)时,你就可以得到它,而不必破坏世界。
  • @NicolBolas 我明白你在说什么,这确实会使这种方法不安全,但除非我错了,在这种情况下,这两种情况都在 2 字节范围内,只有一个代码点两个字符。所以,还是很奇怪?
  • @Peter:你的towupper 可能只是包装CharUpperW,我在网上找到了一个实现,它就是这样做的。但是您可以从 unicode.org 下载最新的代码点细分,或者为您需要的代码制作一个简单的一对一映射集,或者(注意 Nicol 对德国 ß 等案例的评论)更长更多多功能的功能。 (请记住,ß > SS 不是问题,但相反。)
【解决方案2】:

在 Windows 上这将起作用: 编辑刚刚意识到您使用的是 Borland,而不是 Msvc。

 #include <cctype>
 #include <clocale>

 int main(int argc, char** argv)
 {
    setlocale(LC_ALL, "polish");

    wchar_t c[2] = { L'ś', L'ć'};
    wchar_t c1 = _towupper_l(c[0], _get_current_locale());
    wchar_t c2 = _towupper_l(c[1], _get_current_locale());

    return 0:
}

您首先需要使用setlocale 将语言环境设置为“polish”。然后使用_towupper_l。 这是一个link,它告诉您哪些字符串(指特定语言)可以与setlocale 一起使用。

编辑: 请注意,如果我打印结果:

_wprintf_l(L" c1 = %c, c2 = %c\n", _get_current_locale(),  c1, c2);

输出将是:

c1 = S, c2 = C

但如果我在调试器中观察 C1 和 C2 的值,我可以看到正确的结果,带有重音符号。我的控制台不会打印那种字符。

【讨论】:

  • 我不一定知道可能传递给例程的每个句子的语言环境,甚至可以在一个句子中包含多种语言。它也打败了开始使用 Unicode。
  • @Peter 你要明白的是,例如在法语中,é 的大写是E,而不是É。但是对于使用字母é 的其他语言,é 的大写是É,而不是E。所以我不知道你问的是否可能,因为一个字母的大写是非常特定于语言的。编辑:在我的帖子中有一个关于可以将哪些字符串传递给setlocale的链接。
  • 我明白你的意思。谢谢。我认为理想的解决方案是让我的翻译人员提供两个字符串。一个小写字符串和一个大写字符串
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-07
  • 2017-12-02
  • 2016-01-19
  • 1970-01-01
相关资源
最近更新 更多