Подтвердить что ты не робот

Измените все буквы с акцентом на обычные буквы в С++

Вопрос

Как вы можете изменить все буквы с акцентом на обычные буквы в С++ (или на C)?

Под этим я подразумеваю что-то вроде eéèêaàäâçc станет eeeeaaaacc.

Что я уже пробовал

Я пробовал просто разбирать строку вручную и заменять каждый из них один за другим, но я думал, что должен быть лучший/более простой способ, о котором я не знаю (что бы гарантировать, что я не забываю никаких акцентированная буква).

Мне интересно, есть ли какая-либо карта где-нибудь в стандартной библиотеке или если все акцентированные символы могут быть легко сопоставлены с "нормальной" буквой, используя некоторую математическую функцию (например, floor(charCode-131/5) + 61)).

4b9b3361

Ответ 1

Сначала вы должны определить, что вы подразумеваете под "акцентированными буквами", что нужно сделать, в значительной степени отличается, если у вас есть некоторые расширенные 8 бит ASCII с национальной кодовой страницей для кодов выше 128 или сказать некоторую строку, закодированную utf8.

Однако вы должны взглянуть на libicu, которые обеспечивают то, что необходимо для правильного манипулирования буквами на основе юникода.

Но это не решит все проблемы для вас. Например, что вы должны делать, если получите китайское или русское письмо? Что вы должны сделать, если получите верхний регистр в Турции? Удалить точку на этом "Я"? Это может изменить смысл текста... и т.д. Подобные проблемы бесконечны с помощью unicode. Даже обычный порядок сортировки зависит от страны...

Ответ 2

char* removeAccented( char* str ) {
    char *p = str;
    while ( (*p)!=0 ) {
        const char*
        //   "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
        tr = "AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiiOnooooo/0uuuuypy";
        unsigned char ch = (*p);
        if ( ch >=192 ) {
            (*p) = tr[ ch-192 ];
        }
        ++p; // http://stackoverflow.com/questions/14094621/
    }
    return str;
}

Ответ 3

Я знаю это только в теории. В основном, вы выполняете нормализацию Юникода, затем декомпозицию, очищаете все диакритики и снова перестраиваете.

Ответ 4

Предполагая, что значения равны только char s, я бы создал массив с требуемыми целевыми значениями, а затем просто заменил каждый символ соответствующим членом в массиве:

char replacement[256];
int n(0);
std::generate_n(replacement, 256, [=]() mutable -> unsigned char { return n++; });
replacement[static_cast<unsigned char>('é')] = 'e';
// ...
std::transform(s.begin(), s.end(), s.begin(),
               [&](unsigned char c){ return replacement[c]; });

Так как вопрос также помечен C: при использовании C вам нужно создать подходящие циклы для выполнения тех же операций, но концептуально это было бы точно так же. Аналогично, если вы не можете использовать С++ 2011, вы просто используете подходящие объекты функций вместо лямбда-функций.

Очевидно, массив replacement можно настроить только один раз и использовать более разумный подход, чем то, что описано выше. Однако принцип должен работать. Если вам нужно заменить символы Unicode, то станет немного интереснее: например, массив будет довольно большим и, кроме того, персонажу может потребоваться несколько слов, которые нужно изменить.

Ответ 5

Вот что вы можете сделать, используя ISO/IEC 8859-1 (стандартная кодировка на основе ASCII):

  • если диапазон кода от 192 - 197 заменить на A
  • если диапазон кода от 224 - 229 заменить на A
  • если диапазон кода от 200 - 203 заменить на E
  • если диапазон кода от 232 - 235 заменить на E
  • если диапазон кода от 204 - 207 заменить на I
  • если диапазон кода от 236 - 239 заменить на I
  • если диапазон кода от 210 - 214 заменить на O
  • если диапазон кода от 242 - 246 заменить на O
  • если диапазон кода от 217 - 220 заменить на U
  • если диапазон кода от 249 - 252 заменить на U

Предположим, что x - код номера, выполните следующие заглавные буквы:

  • y = floor((x - 192) / 6)
  • if y <= 2, затем z = ((y + 1) * 4) + 61 else z = (y * 6) + 61

Выполните следующие действия для небольших букв:

  • y = floor((x - 224) / 6)
  • if y <= 2, затем z = ((y + 1) * 4) + 93 else z = (y * 6) + 93

Окончательный ответ z - это код ASCII нужного алфавита.
Обратите внимание, что этот метод работает, только если вы используете ISO/IEC 8859-1.

Ответ 6

Я боюсь, что здесь нет легкого пути.

В приложении, которое я работаю над этим, было решено с помощью внутренних таблиц кодовой страницы, каждая таблица кодовых страниц (например, 1250, 1251, 1252 и т.д.) содержала фактическую кодовую страницу и недиакритический эквивалент. Таблицы были автоматически сгенерированы с использованием С#, в нем содержатся некоторые классы, которые действительно делают это очень просто (с некоторыми эвристиками), а также java позволяет реализовать его quicly.

Это было фактически для многобайтовых данных с кодовыми страницами, но его можно было использовать для строк UNICODE (просто выполнив поиск всех таблиц для данной буквы в Юникоде).

Ответ 7

Моему варианту использования понадобилось сделать нечувствительный к регистру сортировку длинного списка строк, где некоторые из строк могут иметь диакритические символы. Так, например, я хотел, чтобы "Añasco Municipio" прибыл прямо перед "Муниципалитетом Анкориджа" вместо того, чтобы идти прямо перед "Графством Абвиль", как это делалось с наивным сравнением.

Мои строки закодированы в UTF-8, но есть вероятность, что они могут содержать некоторые расширенные символы ascii вместо правильного Unicode UTF-8. Я мог бы продвигать все строки в UTF-8, а затем использовать библиотеку, которая могла бы выполнять сравнение строк UTF-8, но я хотел иметь полный контроль как для скорости, так и для того, чтобы точно определить, как диакритические символы отображаются на недиакритические символы. (Мои варианты включают в себя такие вещи, как обращение с мужским порядковым индикатором как "o" и обработка символа авторского права как c.)

Ниже приведены два байтовых кода: UTF-8. "Однобайтовые" коды расширены ascii.

Здесь я получил коды:

http://www.ascii-code.com/

http://www.endmemo.com/unicode/unicodeconverter.php

void SimplifyStringForSorting( string *s, bool changeToLowerCase )
{
    // C0 C1 C2 C3 C4 C5 E0 E1 E2 E3 E4 E5 AA // one-byte codes for "a"
    // C3 80 C3 81 C3 82 C3 83 C3 84 C3 85 C3 A0 C3 A1 C3 A2 C3 A3 C3 A4 C3 A5 C2 AA // two-byte codes for "a"

    // C8 C9 CA CB E8 E9 EA EB // one-byte codes for "e"
    // C3 88 C3 89 C3 8A C3 8B C3 A8 C3 A9 C3 AA C3 AB // two-byte codes for "e"

    // CC CD CE CF EC ED EE EF // one-byte codes for "i"
    // C3 8C C3 8D C3 8E C3 8F C3 AC C3 AD C3 AE C3 AF // two-byte codes for "i"

    // D2 D3 D4 D5 D6 F2 F3 F4 F5 F6 BA // one-byte codes for "o"
    // C3 92 C3 93 C3 94 C3 95 C3 96 C3 B2 C3 B3 C3 B4 C3 B5 C3 B6 C2 BA // two-byte codes for "o"

    // D9 DA DB DC F9 FA FB FC // one-byte codes for "u"
    // C3 99 C3 9A C3 9B C3 9C C3 B9 C3 BA C3 BB C3 BC // two-byte codes for "u"

    // A9 C7 E7 // one-byte codes for "c"
    // C2 A9 C3 87 C3 A7 // two-byte codes for "c"

    // D1 F1 // one-byte codes for "n"
    // C3 91 C3 B1 // two-byte codes for "n"

    // AE // one-byte codes for "r"
    // C2 AE // two-byte codes for "r"

    // DF // one-byte codes for "s"
    // C3 9F // two-byte codes for "s"

    // 8E 9E // one-byte codes for "z"
    // C5 BD C5 BE // two-byte codes for "z"

    // 9F DD FD FF // one-byte codes for "y"
    // C5 B8 C3 9D C3 BD C3 BF // two-byte codes for "y"

    int n = s->size();
    int pos = 0;
    for ( int i = 0 ; i < n ; i++, pos++ )
    {
        unsigned char c = (unsigned char)s->at( i );
        if ( c >= 0x80 )
        {
            if ( i < ( n - 1 ) && (unsigned char)s->at( i + 1 ) >= 0x80 )
            {
                unsigned char c2 = SimplifyDoubleCharForSorting( c, (unsigned char)s->at( i + 1 ), changeToLowerCase );
                if ( c2 < 0x80 )
                {
                    s->at( pos ) = c2;
                    i++;
                }
                else
                {
                    // s->at( pos ) = SimplifySingleCharForSorting( c, changeToLowerCase );
                    // if it a double code we don't recognize, skip both characters;
                    // this does mean that we lose the chance to handle back-to-back extended ascii characters
                    // but we'll assume that is less likely than a unicode "combining character" or other
                    // unrecognized unicode character for data
                    i++;
                }
            }
            else
            {
                unsigned char c2 = SimplifySingleCharForSorting( c, changeToLowerCase );
                if ( c2 < 0x80 )
                {
                    s->at( pos );
                }
                else
                {
                    // skip unrecognized single-byte codes
                    pos--;
                }
            }
        }
        else
        {
            if ( changeToLowerCase && c >= 'A' && c <= 'Z' )
            {
                s->at( pos ) = c + ( 'a' - 'A' );
            }
            else
            {
                s->at( pos ) = c;
            }
        }
    }
    if ( pos < n )
    {
        s->resize( pos );
    }
}

unsigned char SimplifyDoubleCharForSorting( unsigned char c1, unsigned char c2, bool changeToLowerCase )
{
    // C3 80 C3 81 C3 82 C3 83 C3 84 C3 85 C3 A0 C3 A1 C3 A2 C3 A3 C3 A4 C3 A5 C2 AA // two-byte codes for "a"
    // C3 88 C3 89 C3 8A C3 8B C3 A8 C3 A9 C3 AA C3 AB // two-byte codes for "e"
    // C3 8C C3 8D C3 8E C3 8F C3 AC C3 AD C3 AE C3 AF // two-byte codes for "i"
    // C3 92 C3 93 C3 94 C3 95 C3 96 C3 B2 C3 B3 C3 B4 C3 B5 C3 B6 C2 BA // two-byte codes for "o"
    // C3 99 C3 9A C3 9B C3 9C C3 B9 C3 BA C3 BB C3 BC // two-byte codes for "u"
    // C2 A9 C3 87 C3 A7 // two-byte codes for "c"
    // C3 91 C3 B1 // two-byte codes for "n"
    // C2 AE // two-byte codes for "r"
    // C3 9F // two-byte codes for "s"
    // C5 BD C5 BE // two-byte codes for "z"
    // C5 B8 C3 9D C3 BD C3 BF // two-byte codes for "y"

    if ( c1 == 0xC2 )
    {
        if ( c2 == 0xAA ) { return 'a'; }
        if ( c2 == 0xBA ) { return 'o'; }
        if ( c2 == 0xA9 ) { return 'c'; }
        if ( c2 == 0xAE ) { return 'r'; }
    }

    if ( c1 == 0xC3 )
    {
        if ( c2 >= 0x80 && c2 <= 0x85 ) { return changeToLowerCase ? 'a' : 'A'; }
        if ( c2 >= 0xA0 && c2 <= 0xA5 ) { return 'a'; }
        if ( c2 >= 0x88 && c2 <= 0x8B ) { return changeToLowerCase ? 'e' : 'E'; }
        if ( c2 >= 0xA8 && c2 <= 0xAB ) { return 'e'; }
        if ( c2 >= 0x8C && c2 <= 0x8F ) { return changeToLowerCase ? 'i' : 'I'; }
        if ( c2 >= 0xAC && c2 <= 0xAF ) { return 'i'; }
        if ( c2 >= 0x92 && c2 <= 0x96 ) { return changeToLowerCase ? 'o' : 'O'; }
        if ( c2 >= 0xB2 && c2 <= 0xB6 ) { return 'o'; }
        if ( c2 >= 0x99 && c2 <= 0x9C ) { return changeToLowerCase ? 'u' : 'U'; }
        if ( c2 >= 0xB9 && c2 <= 0xBC ) { return 'u'; }
        if ( c2 == 0x87 ) { return changeToLowerCase ? 'c' : 'C'; }
        if ( c2 == 0xA7 ) { return 'c'; }
        if ( c2 == 0x91 ) { return changeToLowerCase ? 'n' : 'N'; }
        if ( c2 == 0xB1 ) { return 'n'; }
        if ( c2 == 0x9F ) { return 's'; }
        if ( c2 == 0x9D ) { return changeToLowerCase ? 'y' : 'Y'; }
        if ( c2 == 0xBD || c2 == 0xBF ) { return 'y'; }
    }

    if ( c1 == 0xC5 )
    {
        if ( c2 == 0xBD ) { return changeToLowerCase ? 'z' : 'Z'; }
        if ( c2 == 0xBE ) { return 'z'; }
        if ( c2 == 0xB8 ) { return changeToLowerCase ? 'y' : 'Y'; }
    }

    return c1;
}

unsigned char SimplifySingleCharForSorting( unsigned char c, bool changeToLowerCase )
{
    // C0 C1 C2 C3 C4 C5 E0 E1 E2 E3 E4 E5 AA // one-byte codes for "a"
    // C8 C9 CA CB E8 E9 EA EB // one-byte codes for "e"
    // CC CD CE CF EC ED EE EF // one-byte codes for "i"
    // D2 D3 D4 D5 D6 F2 F3 F4 F5 F6 BA // one-byte codes for "o"
    // D9 DA DB DC F9 FA FB FC // one-byte codes for "u"
    // A9 C7 E7 // one-byte codes for "c"
    // D1 F1 // one-byte codes for "n"
    // AE // one-byte codes for "r"
    // DF // one-byte codes for "s"
    // 8E 9E // one-byte codes for "z"
    // 9F DD FD FF // one-byte codes for "y"

    if ( ( c >= 0xC0 && c <= 0xC5 ) || ( c >= 0xE1 && c <= 0xE5 ) || c == 0xAA )
    {
        return ( ( c >= 0xC0 && c <= 0xC5 ) && !changeToLowerCase ) ? 'A' : 'a';
    }

    if ( ( c >= 0xC8 && c <= 0xCB ) || ( c >= 0xE8 && c <= 0xEB ) )
    {
        return ( c > 0xCB || changeToLowerCase ) ? 'e' : 'E';
    }

    if ( ( c >= 0xCC && c <= 0xCF ) || ( c >= 0xEC && c <= 0xEF ) )
    {
        return ( c > 0xCF || changeToLowerCase ) ? 'i' : 'I';
    }

    if ( ( c >= 0xD2 && c <= 0xD6 ) || ( c >= 0xF2 && c <= 0xF6 ) || c == 0xBA )
    {
        return ( ( c >= 0xD2 && c <= 0xD6 ) && !changeToLowerCase ) ? 'O' : 'o';
    }

    if ( ( c >= 0xD9 && c <= 0xDC ) || ( c >= 0xF9 && c <= 0xFC ) )
    {
        return ( c > 0xDC || changeToLowerCase ) ? 'u' : 'U';
    }

    if ( c == 0xA9 || c == 0xC7 || c == 0xE7 )
    {
        return ( c == 0xC7 && !changeToLowerCase ) ? 'C' : 'c';
    }

    if ( c == 0xD1 || c == 0xF1 )
    {
        return ( c == 0xD1 && !changeToLowerCase ) ? 'N' : 'n';
    }

    if ( c == 0xAE )
    {
        return 'r';
    }

    if ( c == 0xDF )
    {
        return 's';
    }

    if ( c == 0x8E || c == 0x9E )
    {
        return ( c == 0x8E && !changeToLowerCase ) ? 'Z' : 'z';
    }

    if ( c == 0x9F || c == 0xDD || c == 0xFD || c == 0xFF )
    {
        return ( ( c == 0x9F || c == 0xDD ) && !changeToLowerCase ) ? 'Y' : 'y';
    }

    return c;
}