gpt4 book ai didi

c++ - 如何在 C++ 中对具有不同编码的文本文件应用 函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:04:34 26 4
gpt4 key购买 nike

我想将一些文件(大约 1000 个)拆分为单词并删除数字和标点符号。然后我将相应地处理这些标记化的词......但是,这些文件大部分是德语,并且以不同的类型编码:

  • ISO-8859-1
  • ISO Latin-1
  • ASCII
  • UTF-8

我面临的问题是我找不到正确的申请方式 Character Conversion functions例如 tolower()当我使用 std::cout 时,我还会在终端中看到一些奇怪的图标在 Ubuntu linux .

例如,在非 UTF-8 文件中,单词 französische显示为franz�sische , für作为 f�r等......另外,像Örebro这样的词或 Österreichtolower() 忽略.据我所知"Unicode replacement character" � (U+FFFD)为程序在尝试处理 Unicode 时无法正确解码的任何字符插入。

当我打开 UTF-8 文件时,我没有看到任何奇怪的字符,但我仍然无法转换大写特殊字符,例如 Ö小写...我用了std::setlocale(LC_ALL, "de_DE.iso88591");以及我在 stackoverflow 上找到的其他一些选项,但我仍然没有得到所需的输出。

我猜我应该如何解决这个问题:

  1. 检查即将打开文件的编码
  2. 根据文件的特定编码打开文件
  3. 将文件输入转换为 UTF-8
  4. 处理文件并申请tolower()等等

就是上面的algorithm可行还是复杂性会飙升?

解决这个问题的正确方法是什么?如何使用某种编码选项打开文件?

<强>1。我的操作系统是否应该启用相应的区域设置作为全局变量来处理(不打扰控制台如何显示它)文本?(例如在 linux 中,当我使用 -locale -a 时我没有启用 de_DE)

<强>2。此问题是否仅由于终端默认编码而可见?在使用 C++ 正常处理提取的字符串之前,我是否需要采取任何进一步的步骤?

我的 Linux 语言环境:

LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=el_GR.UTF-8
LC_TIME=el_GR.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=el_GR.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=el_GR.UTF-8
LC_NAME=el_GR.UTF-8
LC_ADDRESS=el_GR.UTF-8
LC_TELEPHONE=el_GR.UTF-8
LC_MEASUREMENT=el_GR.UTF-8
LC_IDENTIFICATION=el_GR.UTF-8
LC_ALL=

C
C.UTF-8
el_GR.utf8
en_AG
en_AG.utf8
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_IN.utf8
en_NG
en_NG.utf8
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZM
en_ZM.utf8
en_ZW.utf8
POSIX

这是我编写的一些示例代码,但无法按我想要的方式运行。

void processFiles() {
std::string filename = "17454-8.txt";
std::ifstream inFile;
inFile.open(filename);
if (!inFile) {
std::cerr << "Failed to open file" << std::endl;
exit(1);
}

//calculate file size
std::string s = "";
s.reserve(filesize(filename) + std::ifstream::pos_type(1));
std::string line;
while( (inFile.good()) && std::getline(inFile, line) ) {
s.append(line + "\n");
}
inFile.close();

std::cout << s << std::endl;
//remove punctuation, numbers, tolower,
//TODO encoding detection and specific transformation (cannot catch Ö, Ä etc) will add too much complexity...
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]);
}
//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>{}};
for (auto & i : tokens)
std::cout << i << std::endl;

//PROCESS TOKENS
return;
}

最佳答案

Unicode 为字符定义了“代码点”。 代码点 是一个 32 位值。

有一些类型的编码。 ASCII 仅使用 7 位,这给出了 128 个不同的字符。微软使用第 8 位来定义另外 128 个字符,这取决于语言环境,称为“代码页”。如今 MS 使用 UTF-16 2 字节编码。因为这对于整个 Unicode 集来说还不够,UTF-16 也依赖于语言环境,其名称与 Unicode 的名称“Latin-1”或“ISO-8859-1”等相匹配。

Linux 中最常用的(通常用于文件)是 UTF-8,它为每个字符使用可变字节数。前 128 个字符与 ASCII 字符完全相同,每个字符只有一个字节。要表示一个字符,UTF8 最多可以使用 4 个字节。更多信息在 Wikipedia .

虽然 MS 对文件和 RAM 使用 UTF-16,但 Linux 可能对 RAM 使用 UFT-32。

为了读取一个文件,你需要知道它的编码。试图检测它是一场真正的噩梦,可能不会成功。 std::basic_ios::imbue的使用允许您为流设置所需的语言环境,如 this SO answer

tolower并且这些功能可以与语言环境一起使用,例如

#include <iostream>
#include <locale>

int main() {
wchar_t s = L'\u00D6'; //latin capital 'o' with diaeresis, decimal 214
wchar_t sL = std::tolower(s, std::locale("en_US.UTF-8")); //hex= 00F6, dec= 246
std::cout << "s = " << s << std::endl;
std::cout << "sL= " << sL << std::endl;

return 0;
}

输出:

s = 214
sL= 246

在这个other SO answer您可以找到很好的解决方案,如使用 iconv Linuxiconv W32图书馆。

在 Linux 中,终端可以在 LC_ALLLANGLANGUAGE 的帮助下设置为使用语言环境>,例如:

//Deutsch
LC_ALL="de_DE.UTF-8"
LANG="de_DE.UTF-8"
LANGUAGE="de_DE:de:en_US:en"

//English
LC_ALL="en_US.UTF-8"
LANG="en_US.UTF-8"
LANGUAGE="en_US:en"

关于c++ - 如何在 C++ 中对具有不同编码的文本文件应用 <cctype> 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49705874/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com