【问题标题】:how to properly apply tolower() on German capital letters Ä, Ö, Ü, ẞ in C++如何在 C++ 中正确地将 tolower() 应用于德语大写字母 Ä、Ö、Ü、ẞ
【发布时间】:2018-04-08 14:46:43
【问题描述】:

我开了一个question有点迷茫,我想在这里说的更具体一点。

我有许多包含德语字母的文件,大部分采用 iso-8859-15UTF-8 编码。为了处理它们,必须将所有字母转换为小写。

例如,我有一个文件(编码为 iso-8859-15 ),其中包含:

博士。玫瑰在 M. Das sogen。 Baptisterium zu Winland, eins der im Art。 "Baukunst" (S. 496) erwähnten Rundgebäude in Grönland, soll nach Palfreys “新英格兰历史” eine von dem Gouverneur Arnold um 1670 erbaute Windmühle sein。 Vgl。阵风。书房里的风暴“Jahrbüchern der” 哥本哈根 königlichen Gesellschaft für nordische Altertumskunde" 1887 年,S. 296。

Ää​​ Öö Üü ẞß Örebro

文本Ää Öö Üü ẞß Örebro 应变为:ää öö üü ßß örebro

但是,tolower() 似乎不适用于 Ä、Ö、Ü、ẞ 等大写字母,尽管我尝试强制使用 this SO post 中提到的语言环境

这是我在另一个问题中发布的相同代码:

std::vector<std::string> tokens;
std::string filename = "10223-8.txt";
//std::string filename = "test-UTF8.txt";
std::ifstream inFile;

//std::setlocale(LC_ALL, "en_US.iso88591");
//std::setlocale(LC_ALL, "de_DE.iso88591");
//std::setlocale(LC_ALL, "en_US.iso88591");
//std::locale::global(std::locale(""));

inFile.open(filename);
if (!inFile) { std::cerr << "Failed to open file" << std::endl; exit(1); }

std::string s = "";
std::string line;
while( (inFile.good()) && std::getline(inFile, line) ) {
    s.append(line + "\n");
}
inFile.close();

std::cout << s << std::endl;

//std::setlocale(LC_ALL, "de_DE.iso88591");
for (unsigned int i = 0; i < s.length(); ++i) {
    if (std::ispunct(s[i]) || std::isdigit(s[i]))
            s[i] = ' ';
    if (std::isupper(s[i]))
            s[i] = std::tolower(s[i]);
            //s[i] = std::tolower(s[i]);
            //s[i] = std::tolower(s[i], std::locale("de_DE.utf8"))
}

std::cout << s << std::endl;

//tokenize string
std::istringstream iss(s);
tokens.clear();
tokens = {std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};

//PROCESS TOKENS...

这真的很令人沮丧,关于&lt;locale&gt;的使用范式并不多。

所以,除了我的代码的主要问题之外,还有一些问题:

  1. 我是否也必须在其他函数中应用某种自定义语言环境(isupper()ispunct()...)?
  2. 我是否需要在我的 linux env 中启用或安装 de_DE 语言环境才能正确处理字符串的字符?
  3. 以同样的方式处理std::string这样的文本是否安全 从具有不同编码(iso-8859-15 或 UTF-8)的文件中提取?

编辑:康拉德鲁道夫的回答仅适用于 UTF-8 文件。它不适用于 iso-8859-15,这会转化为此处发布的初始问题: How to apply functions on text files with different encoding in c++

【问题讨论】:

  • 有些字母不能没有小写表示。有些可以但不往返。
  • 我非常幸运地制作了自己的翻译表。如果我是你,我会将 ISO 8859-15 翻译成 Unicode。在您的代码中,您似乎尝试以各种排列方式使用 ISO 8859-1。 ISO 8859-15 不是 ISO 8859-1。
  • @RichardCritten 我提到的那些都是大写的吗?
  • 您的系统上可能未正确设置区域设置。您应该尝试以下问题的解决方案:stackoverflow.com/questions/19100708
  • C++ 在编码方面是一种标准的平底船。 std::locale 受操作系统提供的支配,而且(在我看来)有点笨拙。我尝试坚持使用 Unicode;大部分是 UTF-8,有时是 WTF-8、UTF-16 或 UTF-32,但我会尽快转换为 UTF-8。任何其他编码我也会尽可能靠近边缘翻译成 Unicode (UTF-8)。我在使用 IBM 的 ICU 时有很好的经验。而且,我承认,有时我使用 Python 3.x 将数据预先整理成 Unicode。

标签: c++ stl character-encoding


【解决方案1】:

使用std::ctype::tolower,而不是std::tolower

#include <iostream>
#include <locale>

int main() {
    std::locale::global(std::locale("de_DE.UTF-8"));
    std::wcout.imbue(std::locale());
    auto& f = std::use_facet<std::ctype<wchar_t>>(std::locale());
    std::wstring str = L"Ää Öö Üü ẞß Örebro";
    f.tolower(&str[0], &str[0] + str.size());
    std::wcout << "'" << str << "'\n";
}

除了设置全局语言环境,您还可以创建一个语言环境(呵呵):

std::locale loc("de_DE.UTF-8");
std::wcout.imbue(loc);
auto& f = std::use_facet<std::ctype<wchar_t>>(loc);

这编译并“工作”。在我的系统上,它可以正确转换变音符号,但无法处理大写字母-ß(说实话,这并不奇怪)。

此外,请注意此函数的局限性:它只能执行 1 对 1 的字符转换。在以前版本的 Unicode 标准中,“ß”的正确大写转换是“SS”。 std::ctype::toupper 明确地从不支持这一点。

【讨论】:

  • 谢谢。您的代码工作正常!它甚至将ẞß 转换为ßß。现在我只需要找到一种方法来使用流和输入文件字符串。
  • 顺便说一句,创建本地语言环境的选项似乎不起作用。此外,由于存在 iso-8859-15 中的文件,我如何使上述示例同时适用于 UTF-8 和 iso-8859-15?只有事先知道文件编码还是可以通过其他方法?
  • @BugShotGG 一般来说,是的,您需要知道文件编码。当然,您可以在运行时根据每个文件来决定。如果您不知道各个文件是如何编码的(总是不好),您可以简单地为每个文件尝试两种语言环境,看看哪一种能提供更好的结果(但如何定义“更好”并非易事)。
  • 在结束这个问题之前,我想问你两个关键问题。为了正确地将 tolow 应用于 iso-8859-15 文件,是否将第一行更改为 std::locale::global(std::locale("de_DE.iso-885915")); ?我对么?还有,在tolower()申请之后,将wstring转换成string安全吗?
  • @BugShotGG 不幸的是,我不确定这两个问题的答案。 (1) 取决于系统。在我的系统上,我必须使用de_DE.ISO8859-15(参见Unix 上的locale -a 输出),这可能不适用于wchar_t。 (2) 你打算如何转换它?在没有外部库的标准 C++ 中,在给定编码中 std::stringstd::wstring 之间的可靠转换是困难的,因为它们都不支持编码。
猜你喜欢
  • 1970-01-01
  • 2019-06-08
  • 2012-06-28
  • 1970-01-01
  • 2015-05-04
  • 2012-07-27
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多