在C++中处理 Unicode 字符
Processing Unicode characters in C++
我有一个文件,其中包含未声明编码的 Unicode 文本。我想扫描此文件,查找 U+0600 到 U+06FF 范围内的任何阿拉伯语码位,并将每个适用的 Unicode 码位映射到 ASCII 的一个字节,以便新生成的文件将由纯 ASCII 字符组成,所有码位都在 128 以下。
我该怎么做? 我试图以与您阅读 ASCII 相同的方式读取它们,但我的终端显示??
因为它是一个多字节字符。
注意:该文件由 Unicode 字符集的子集组成,子集大小小于 ASCII 字符的大小。因此,我能够从这个特定的 Unicode 子集到 ASCII 进行 1:1 映射。
这要么是不可能的,要么是微不足道的。以下是一些简单的方法:
-
如果没有码位超过 127,则只需用 ASCII 将其写出即可。 做。
-
如果某些码位超过 127,则必须选择如何用 ASCII 表示它们。一种常见的策略是使用 XML 语法,如 U+03B1 的
α
。 对于转录的每个跨 ASCII Unicode 代码点,这将最多占用 8 个 ASCII 字符。
不可能的那些我留给原始海报作为练习。 我什至不会提到愚蠢但可能(阅读:愚蠢(的方法,因为这些方法很多。数据销毁是数据处理中的死罪,应按此处理。
请注意,我假设"Unicode 字符"实际上是指"Unicode 代码点";即程序员可见的字符。 对于用户可见的字符,您需要"Unicode 字形(集群("。
此外,除非你先规范化你的文本,否则你会讨厌这个世界。我建议NFD。
编辑
经过原始海报的进一步澄清,似乎他想做的事情很容易使用现有工具完成,而无需编写新程序。 例如,这会将一组特定的阿拉伯字符从 UTF-8 输入文件转换为 ASCII 输出文件:
$ perl -CSAD -Mutf8 -pe 'tr[ابتثجحخد][abttjhhd]' < input.utf8 > output.ascii
这仅处理以下代码点:
U+0627 ا ARABIC LETTER ALEF
U+0628 ب ARABIC LETTER BEH
U+0629 ة ARABIC LETTER TEH MARBUTA
U+062A ت ARABIC LETTER TEH
U+062B ث ARABIC LETTER THEH
U+062C ج ARABIC LETTER JEEM
U+062D ح ARABIC LETTER HAH
U+062E خ ARABIC LETTER KHAH
U+062F د ARABIC LETTER DAL
因此,您必须将其扩展到所需的任何映射。
如果你想在脚本而不是命令行工具中使用它,它也很容易,另外,你可以通过设置映射来按名称讨论字符,例如:
"N{ARABIC LETTER ALEF}" => "a",
"N{ARABIC LETTER BEH}" => "b",
"N{ARABIC LETTER TEH}" => "t",
"N{ARABIC LETTER THEH}" => "t",
"N{ARABIC LETTER JEEM}" => "j",
"N{ARABIC LETTER HAH}" => "h",
"N{ARABIC LETTER KHAH}" => "h",
"N{ARABIC LETTER DAL}" => "d",
如果这应该是更大C++程序中的一个组件,那么也许你会希望用C++来实现它,可能但不是必需的,使用 ICU4C 库,其中包括音译支持。
但是,如果您只需要一个简单的转换,我不明白为什么要编写专用的C++程序。 似乎工作量太大了。
除非您知道格式,否则无法读取数据。 使用Microsoft Word打开文件,然后转到"另存为","其他格式","纯文本(.txt(",保存。 在转换框中,选择"其他编码","Unicode"(UTF16LE(和"确定"。 该文件现在另存为UTF16LE。
std:ifstream infile("myfile.txt", std::ios::binary); //open stream
infile.seekg (0, ios::end); //get it's size
int length = infile.tellg();
infile.seekg (0, ios::beg);
std::wstring filetext(length/2); //allocate space
ifstream.read((char*)&filetext[0], length); //read entire file
std::string final(length/2);
for(int i=0; i<length/2; ++i) { //"shift" the variables to "valid" range
if (filetext[length/2] >= 0x600 && filetext[length/2] <= 0xFF)
final[length/2] = filetext[length/2]-0x600;
else
throw std::exception("INVALID CHARACTER");
}
//done
到处都是警告:我非常怀疑这会产生你想要的结果,但这是可以管理的最好的,因为你还没有告诉我们需要做的翻译,或者文件的格式。 另外,我假设您的计算机和编译器与我的相同。 如果没有,部分或全部可能是错误的,但这是我能做的最好的事情,你没有告诉我们这些缺失的信息。
为了解析出 Unicode 代码点,您必须首先将文件解码为其未编码的 Unicode 表示形式(等效于 UTF-32(。 为此,您首先需要知道文件是如何编码的,以便可以对其进行解码。 例如,Unicode 代码点U+0600
和U+06FF
以 UTF-8 编码为0xD8 0x80
和0xDB 0xBF
,在 UTF-16LE 中编码为0x00 0x06
和0xFF 0x06
,以 UTF-16BE 编码为0x06 0x00
和0x06 0xFF
,等等。
如果文件以 BOM 开头,则您知道使用的确切编码,并且可以相应地解释文件的其余部分。 例如,UTF-8 BOM 是0xEF 0xBB 0xBF
的,UTF-16LE 是0xFF 0xFE
的,UTF-16BE 是0xFE 0xFF
的,等等。
如果文件不是以 BOM 开头,则必须分析数据并对其执行启发式以检测编码,但这不是 100% 可靠的。 尽管检测 UTF 编码相当容易,但几乎不可能以任何可靠性来检测 Ansi 编码。 即使检测没有 BOM 的 UTF 编码有时也会导致错误的结果(阅读这个、这个和这个(。
永远不要猜测,您将面临数据丢失的风险。 如果您不知道使用的确切编码,请向用户询问。
- 如何存储 unicode 字符并将其输出到文件?
- C++:打印 Unicode 字符
- 在 Windows 中使用 boost::p rogram_options 从命令行参数读取 Unicode 字符
- 获取Unicode字符C++的十进制值
- 用wchar_t处理 unicode 字符好吗?它不会引起任何问题吗?
- C++:如何将 unicode 字符打印到文本文件
- 动态计算 unicode 字符
- 如何将整数转换为 unicode 字符
- C++20 中的严格别名规则是否允许标准 c++ unicode 字符和下划线类型之间"reinterpret
- MessageBox打印来自TCHAR缓冲区的额外Unicode字符
- 如何将小数NCR转换为Unicode字符(C )
- SQLGetPrivateProfileString 错误地读取 Unicode 字符
- 将 Unicode 字符/字符串写入文件
- 将 Unicode 字符存储在.txt文件中的新行中
- 从终端 C++ 中的字符串中打印出 unicode 字符
- Unicode 字符分类与 boost::locale
- 字符数组中的滤波器unicode字符
- Unicode 字符问题/转换参数
- 从包含Unicode字符的文件中读取
- 从ASCII到Unicode字符代码的转换(FreeType2)