【问题标题】:C++ String to lowercase with custom locale使用自定义语言环境将 C++ 字符串转换为小写
【发布时间】:2017-02-26 14:57:58
【问题描述】:

我一直在尝试使用不同的语言环境调用std::tolower(),但似乎出了点问题。我的代码如下:

int main() {
    std::locale::global(std::locale("es_ES.UTF-8"));
    std::thread(&function, this); // Repeated some times
    // wait for threads
}

void function() {
    std::string word = "HeÉllO";
    std::transform(word.begin(), word.end(), word.begin(), cToLower);
}

int cToLower(int c) {
    return std::tolower(c, std::locale());
}

所以当我尝试执行这个程序时,我得到:

terminate called after throwing an instance of 'std::bad_cast'
terminate called recursively
  what():  std::bad_cast
Aborted (core dumped)

虽然执行 return std::tolower(c); 工作正常,但它只是将“标准”字符转换为小写,而不是 É。

我有一些线程同时执行相同的函数,使用 C++11 并使用 g++ 编译(以防它与它有关)。

我想知道这是否是实现我想做的正确方法,或者还有其他方法。

谢谢!

【问题讨论】:

  • 尝试找出问题出在线程还是语言环境。 1.) 它在单线程程序中工作吗? 2.) 它是否适用于多线程程序中的英文字符串和默认语言环境?
  • 试试std::tolower((unsigned char)c, std::locale())。来自the documentation:“如果ch 的值不能表示为无符号字符且不等于EOF,则行为未定义。”问题是,char 通常是有符号的,而像É 这样的字符被表示为负值,然后超出了unsigned char 的范围
  • @IgorTandetnik,正确!。请回答。 :-)
  • @IgorTandetnik 仍然抛出了 bad_cast。我理解你提出的逻辑,但看起来我必须改用 wstring。
  • @IgorTandetnik 这仅适用于 C 标准库中的单参数版本,不适用于 C++ <locale> 中的双参数版本。

标签: c++ locale tolower


【解决方案1】:

与来自 C 的 tolower 版本不同(它将字符转换为 unsigned char,然后转换为 int),<locale> 版本的 tolower 旨在直接使用字符调用。它被定义为使用语言环境的std::ctype<charT> facet,唯一的两个std::ctype 特化guaranteed to be available 是std::ctype<char> 和std::ctype<wchar_t>。因此:

char cToLower(char c) {
    return std::tolower(c, std::locale());
}

请注意,这仍然是char-by-char 转换;如果字符占用超过一个字节,则不太可能正确处理。

【讨论】:

  • 感谢您的回复!我明白你的意思,但虽然这可以编译,但它不会将É 等特殊字符转换为é。
  • @lpares12 好吧,我无法测试它,但É 实际上是单个char 吗?如果它实际上需要超过一个字节,那么逐字节转换(这就是你正在做的)不会削减它。
  • É 和 é 在十进制中分别表示为 144 和 130,因此两者都应该放在一个字节内。不过现在想起来应该是unsigned char,否则都是负值。
  • @lpares12 好吧,U+00C9(“LATIN CAPITAL LETTER E WITH ACUTE”)在 UTF-8 中被编码为两个字节,对于 U+00E9(“LATIN SMALL LETTER E WITH ACUTE”)也是如此.我不确定您使用的是什么编码。
【解决方案2】:

检查您尝试使用的语言环境是否安装在您的系统上。例如,我必须在下面的代码停止崩溃之前安装西班牙语语言环境。 此外,您可以改用wstring。 更新:经过一番挖掘后,here 很好地解释了使用 wstring - 所有的缺点和过程(主要是缺点)。

#include <thread>
#include <locale>
#include <algorithm> 
#include <iostream>

//forward declaration
void function();

int main() {
    std::locale::global(std::locale("es_ES.utf8"));
    std::thread test(&function);
    test.join();
}

wchar_t cToLower(wchar_t c) {        
    return std::tolower(c, std::locale());    
}

void function() {
    std::wstring word = L"HeÉllO";
    std::transform(word.begin(), word.end(), word.begin(), cToLower);
    std::wcout << word;
}

输出:

heéllo

【讨论】:

  • 它确实可以使用wstring,但我真的需要使用string。没有其他选择吗?
  • 什么意思不起作用 - 崩溃或小写尚未应用?
  • 它确实有效 :) 但我需要一个解决方法来改用 std::string。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-27
  • 1970-01-01
  • 2016-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多