C - 如何避免变音符号/重音敏感问题

Posted

技术标签:

【中文标题】C - 如何避免变音符号/重音敏感问题【英文标题】:C - How to avoid diacritic/accents sensitive issues 【发布时间】:2016-11-20 10:08:13 【问题描述】:

我正在创建一个猜测国家首都的小程序。一些大写字母有重音、变音符等。

由于我必须比较用户猜测的大写和文本,而且我不想让口音混淆比较,所以我去网上挖掘了一些方法来实现这一点。

我遇到了无数其他编程语言的解决方案,但只有几个关于 C 的结果。

他们都没有真正和我一起工作。不过,我得出的结论是,我必须使用 wchar.h 库来处理那些烦人的字符

我编写了一小段代码(将 É 替换为 E)只是为了检查此方法,并且根据我阅读和理解的所有内容,它不起作用,即使打印宽字符字符串也不会显示变音符号。如果它有效,我相信我可以在首都的计划中实施它,所以如果有人能告诉我出了什么问题,我将不胜感激。

#include<stdio.h>
#include<locale.h>
#include<wchar.h>

const wchar_t CAPITAL_ACCUTE_E = L'\u00C9';

int main()

    wchar_t wbuff[128];
    setlocale(LC_ALL,"");
    fputws(L"Say something: ", stdout);
    fgetws(wbuff, 128, stdin);
    int n;
    int len = wcslen(wbuff);
    for(n=0;n<len;n++)
        if(wbuff[n] == CAPITAL_ACCUTE_E)
            wbuff[n] = L'E';
    wprintf(L"%ls\n", wbuff);
    return 0;

【问题讨论】:

这是标准 C 中的一个有问题的主题。首先明确您的平台使用哪种输入编码,然后采取适当的措施。 正如@Olaf 所说:您需要知道输入编码。您的示例适用于 bash 中的 LANG=en_US.UTF-8 (我 C&P 您的行“将 É 替换为 E”作为输入)。您已经使用setlocale(3),只需阅读输出并采取相应措施(如果您问我,这是最难的部分)。 使用char,我使用tolower(toupper(ch)) 来折叠和再次折叠“相似”的字母。也许是wchar_t 等价物?也许towctrans() 【参考方案1】:

您忽略的一个问题是É 可以表示为

É - LATIN CAPITAL LETTER E WITH ACUTE,代码点 U+00C9(c3 89 UTF-8),或 É - LATIN CAPITAL LETTER E 后跟 COMBINING ACUTE ACCENT,代码点 U+0045 U+0301(45 cc 81 在 UTF-8 中)

您需要考虑这一点。这可以通过将两个字符串映射到NFD (Normal Form: Decomposed) 来完成。之后,您可以剥离分解的组合字符并留下E,然后您可以照常使用strcmp

假设你有一个 UTF-8 编码的input,下面是你如何使用utf8proc:

#include <utf8proc.h>

utf8_t *output;
ssize_t len = utf8proc_map((uint8_t*)input, 0, &output, 
                           UTF8PROC_NULLTERM | UTF8PROC_STABLE |
                           UTF8PROC_STRIPMARK | UTF8PROC_DECOMPOSE |
                           UTF8PROC_CASEFOLD
                          );

这会将所有ÉÉE 变成一个普通的e

【讨论】:

以上是关于C - 如何避免变音符号/重音敏感问题的主要内容,如果未能解决你的问题,请参考以下文章

Android,变音符号不敏感 SQLite 搜索

Ruby 超级不敏感的正则表达式将学校名称与口音和其他变音符号匹配

如何从 .NET 中的字符串中删除变音符号(重音符号)?

如何从 .NET 中的字符串中删除变音符号(重音符号)?

在 JavaScript 中删除字符串中的重音符号/变音符号

LUA:如何正确读取带有重音字母和变音符号的 UFT8 文件名和路径?