带有重音的字符,在C中没有重音

时间:2010-09-15 21:15:52

标签: c diacritics

嘿伙计们。简单的问题:如何从char中删除重音?喜欢ã - > a,和é - >即我在另一个问题中询问如何将utf-8转换为ascii,但这是不必要的,因为我只需要处理这些情况。

我试过了:

char comando;
if( comando == 'ç' || comando == 'Ç') {
        comando = 'c';
        return comando;
    }

但它给了我这个错误:“由于数据类型的范围有限,比较总是错误的。”

我无法确定我的老师要编译我的程序的GCC版本,但她会在Linux上运行它(可能是Ubuntu)。我不能使用标准的lib。 :(

谢谢!

3 个答案:

答案 0 :(得分:3)

C标准表示诸如'ç'之类的字符常量是整数常量:

  

§6.4.4.4/ 9

     

整数字符常量的类型为int。整数字符常量的值   包含映射到单字节执行字符的单个字符是   解释为整数的映射字符表示的数值。

如果在您的机器上签署了char类型(它在Linux上),那么当comando包含'ç'并且被提升为整数时,它将变为负整数,而'ç'是一个正整数。因此来自编译器的警告。


对于8位字符集,到目前为止,执行此类操作的最快方法是创建一个256字节的表,其中每个位置包含字符的非重音版本。

int unaccented(int c)
{
     static const char map[256] =
     {
          '\x00', '\x01', ...
          ...
          '0',    '1',    '2', ...
          ...
          'A',    'B',    'C', ...
          ...
          'a',    'b',    'c', ...
          ...
          'A',    'A',    'A', ... // 0xC0 onwards...
          ...
          'a',    'a',    'a', ... // 0xE0 onwards...
          ...
     };
     if (c < 0 || c > 255)
         return EOF;
     else
         return map[c];
}

当然,你要编写一个程序 - 可能是一个脚本 - 来生成数据表,而不是手动完成。在0..127范围内,位置x处的字符是代码为x的字符(所以map['A'] == 'A')。

如果允许您使用C99,则可以使用指定的初始化程序来改进表格:

static const char map[] =
{
    ['\x00'] = '\x00', ...
    ['A']    = 'A', ...
    ['a']    = 'a', ...
    ['å']    = 'a', ...
    ['Å']    = 'A', ...
    ['ÿ']    = 'y', ...
};

你应该用 diphthongs 字母来做什么,例如'æ'或'ß'没有等效的ASCII;然而,“当有疑问时,不要改变它”的简单规则可以合理地应用。它们不是重音字符,但它们也不是ASCII字符。

这对UTF-8来说效果不佳。为此,您需要更多专门的表,这些表来自Unicode标准中的数据。

另请注意,在调用此函数之前,您应该将任何'char'值强制为'unsigned char'。也就是说,该代码也可能试图与滥用者打交道。但是,当人们在调用函数时不小心时,很难将'ÿ'(0xFF)与EOF区分开来。 C标准字符测试宏需要支持所有有效字符值(当转换为unsigned char时)和EOF作为输入 - 这遵循该设计。

  

§7.4/ 1

     

在所有情况下,参数都是一个int,其值应为   可表示为无符号字符或等于宏EOF的值。如果   参数有任何其他值,行为未定义。

答案 1 :(得分:3)

作为其他答案的补充,请尝试以下尺寸:

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

int main(int argc, char** argv)
{
    wchar_t* x = calloc(100, sizeof(wchar_t));
    char*    y = calloc(100, sizeof(char));

    printf("Input something: ");
    fread(y, 1, 99, stdin);

    mbstowcs(x, y, 100);

    if ( x[0] = L'è' )
    {
        printf("Ohhh, french character!\n");
    }


    free(y); free(x);

    return 0;
}

此代码向您展示了两件事:首先,如何将您读入的多字节字符串转换为宽字符串。从那里,你可以处理几乎所有存在的角色(理论上至少)。

完成此操作后,您只需要一个字符映射及其变换,这样您就可以解析每个字符并将其映射到其他字符。 请参阅此

的其他答案

一些注意事项:我在输入输入时故意在stdin - ctrl + D上使用fread()。这是为了防止缓冲区溢出攻击,如果将结果传递给函数,则容易使用scanf(参见NOP底座)。

其次,我盲目地假设y的输入主要是单字节。事实是,如果在多字节字符串中每个字符使用两个字节,则100个字符= 50个wchar_t字符。我也可以检查长度等,但这超出了本例的范围。

答案 2 :(得分:2)

你在另一个类似的问题中提到,这很容易用你知道的其他语言做。如果我是你并且找不到一个很好的方法来使用C中的可用代码并且需要在C中执行此操作,我会用另一种语言编写一个程序来生成一个C函数,它将为您进行转换。只要你可以循环遍历所有字符,这应该不会太困难,尽管它可能是大代码。我可能会为utf-16做这个,只需要一个简单的包装函数,它接受utf-8,将它们转换为utf-16,并调用转换函数。

转换函数只能由一个非常大的switch / case语句组成,默认情况下是没有转换的字符。