Символ с акцентом на символ без акцента в С - PullRequest
2 голосов
/ 16 сентября 2010

Привет, ребята.простой вопрос: как убрать акценты с символа?Как ã -> а, и é -> е.Я спросил в другом вопросе, как преобразовать utf-8 в ascii, но это не нужно, поскольку мне нужно только обработать эти ситуации.

Я пытался:

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

Но это дает мне этоошибка: «сравнение всегда ложно из-за ограниченного диапазона типов данных».

Я не могу быть уверен в версии GCC, что мой учитель собирается скомпилировать мою программу, но она запустит ее в Linux(Ubuntu, вероятно).И я не могу использовать стандартную библиотеку.: (

Спасибо!

Ответы [ 3 ]

3 голосов
/ 16 сентября 2010

В дополнение к другим ответам, попробуйте это для размера:

#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;
}

Этот код показывает вам две вещи: во-первых, как преобразовать прочитанную вами многобайтовую строку в строку широких символов,Оттуда вы можете обрабатывать почти каждый существующий символ (по крайней мере, теоретически).

Сделав это, вам просто нужна карта символов и их преобразование, которое позволит вам проанализировать каждый символ и сопоставить его с чем-тоостальное. См. Другие ответы для этого

Некоторые примечания: я намеренно использовал fread() в stdin - ctrl + D, когда закончил ввод ввода.Это сделано для того, чтобы предотвратить атаку переполнения буфера, если вы передадите результат в функцию (см. След NOP), вы были бы уязвимы для использования scanf.

Во-вторых, я слепо предполагал, что ввод y будет в основном однобайтовым.Дело в том, что если в многобайтовой строке два байта используются для каждого символа, 100 символов символов = 50 символов wchar_t.Я мог бы также проверить длины и т. Д., Но это выходит за рамки этого примера.

3 голосов
/ 16 сентября 2010

Стандарт C говорит, что символьные константы, такие как 'ç', являются целочисленными константами:

§6.4.4.4 / 9

Целочисленная символьная константа имеет тип int.Значение целочисленной символьной константы, содержащей один символ, который отображается на однобайтовый исполнительный символ, является числовым значением представления сопоставленного символа, интерпретируемого как целое число.

Если тип символа равенподписанный на вашем компьютере (это в 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', ...
};

Не совсем понятно, что вы должны делать с дифтонгами буквами, такими как 'æ' или 'ß', которые не имеют эквивалента ASCII;однако простое правило «когда сомневаешься, не меняй его» можно применять разумно.Это не акцентированные символы, но и не символы ASCII.

Это не очень хорошо работает для UTF-8.Для этого вам нужны более специализированные таблицы, основанные на данных в стандарте Unicode .

Также обратите внимание, что перед вызовом этого вы должны привести любое значение 'char' к 'unsigned char'.Тем не менее, кодекс может также попытаться справиться с нарушителями.Однако трудно отличить «ÿ» (0xFF) от EOF, когда люди неосторожны при вызове функции.Стандартные символьные тестовые макросы C должны поддерживать все допустимые символьные значения (при преобразовании в unsigned char) и EOF в качестве входных данных - это соответствует этой схеме.

§7.4 / 1

Во всех случаях аргументом является int, значение которого должно быть представлено как беззнаковый символ или должно равняться значению макроса EOF.Если аргумент имеет любое другое значение, поведение не определено.

2 голосов
/ 16 сентября 2010

Вы упомянули в другом подобном вопросе, что это было достаточно легко сделать на других языках, которые вы знаете. Если бы я был вами и не смог бы найти хороший способ сделать это с помощью доступного кода на C, и мне нужно было бы сделать это на C, я написал бы программу на другом языке, чтобы сгенерировать функцию C, которая бы выполняла преобразование для вас. Пока вы можете циклически проходить все символы, это не должно быть слишком сложным, хотя это может быть большой код. Я, вероятно, сделал бы это для utf-16, и у меня была бы простая функция-обертка, которая взяла utf-8, преобразовала их в utf-16 и вызвала функцию преобразования.

Функция преобразования была бы просто сделана из очень большого оператора switch / case, и регистр по умолчанию был бы для символов, которые не преобразовывались.

...