如何将宽字符串转换为ASCII

How to convert wide string to ASCII

本文关键字:转换 ASCII 字符串      更新时间:2023-10-16

我正在寻找一种将wstring转换为仅包含ASCII字符的普通string的方法。ASCII(0-127)中不存在的任何字符都应转换为最接近的ASCII字符。如果没有类似的ASCII字符,则应省略该字符。

为了说明,让我们假设以下宽字符串:

wstring text(L"A naïve man called 晨 was having piña colada and crème brûlée.");

我要找的转换版本是这样的(注意没有变音符号):

string("A naive man called  was having pina colada and creme brulee.")

编辑:

关于目的:我正在编写一个分析英语文本的应用程序。输入文件为UTF-8,可能包含特殊字符。我的应用程序的一部分使用了一个用C编写的库,该库只理解ASCII。因此,我需要一种在不丢失太多信息的情况下将文本"静音"为ASCII的方法。

关于精确要求:任何ASCII字符的变音符号版本的字符都应转换为该ASCII字符;应省略所有其他字符。因此,ıĩî应该变成i,因为它们都是小拉丁字母i的版本。另一方面,字符ɩ(iota)虽然在视觉上相似,但不是小拉丁字母i的版本,因此应该省略。

在GitHub上,有一个unidecode cxx,它是节点unidecode的一个(有些未完成)C++端口,它又是Perl的Text::Unicode的JavaScript端口。C++版本的边缘有点粗糙,但src/unidecode.cxx中的示例可以修改为转换示例字符串

A naïve man called 晨 was having piña colada and crème brûlée.

如下:

A naive man called Chen was having pina colada and creme brulee.

为了在没有Gyp的情况下编译代码(这是我从未使用过的,现在也没有时间弄清楚),我不得不对代码进行一些修改(快速而肮脏):

  • #include <iostream>添加到src/unidecode.cxx,并添加以下main例程:

    int main() {
    string output_buf;
    string input_buf = "A naïve man called 晨 was having piña colada and crème brûlée.";
    unidecode(&input_buf, &output_buf);
    cout << output_buf.c_str() << endl;
    }
    
  • src/data.cxx中所有提及的NULL替换为nullptr

然后我用编译

g++ -std=c++11 -o unidecode unidecode.cxx

以获得期望的结果。

该代码看起来像一个相当原始的端口,可以进行一些改进,特别是在更"合适"的C++中。它在内部使用静态编译的转换表,如果不这样做,则可能会对其进行调整以满足您的需求。

wstringwcharstring,它是一个大小可能为2或4字节的字符。同时,UTF8是具有1-4字节的符号大小的可变长度编码。所以你的要求并不完全一致。

假设您已经弄清楚数据是如何准确地存储在字符串中的,我建议您查看ICU库以进行进一步的转换。

您可以规范化字符串,然后删除所有变音符号。但你仍然会留下希腊语、西里尔语之类的东西。或者你可以使用音译功能,这更像你想要的。

mindriot的解决方案更简洁,但仍然需要将wstring转换为正确的UTF8序列。