Код для удаления диакритических знаков с помощью ICU

Может ли кто-нибудь предоставить образец кода для удаления диакритических знаков (например, заменить символы, имеющие диакритические знаки, умляуты и т. Д., Их эквивалентами символов без акцента, без преувеличения и т. Д., Например, каждый знак é с акцентом стал бы простым ASCII e) из UnicodeString с помощью библиотеки ICU на C ++? Например.:

UnicodeString strip_diacritics( UnicodeString const &s ) {
    UnicodeString result;
    // ...
    return result;
}

Предположим, что s уже был нормализован. Спасибо.


person Paul J. Lucas    schedule 07.06.2010    source источник
comment
Дубликат: stackoverflow.com/questions/331279/?   -  person Ben Burnett    schedule 07.06.2010
comment
Ни в этом вопросе, ни в каких-либо других ответах не используется библиотека ICU.   -  person Paul J. Lucas    schedule 07.06.2010
comment
Ну и что? Важный шаг - разложить строку, а затем отфильтровать диакритические знаки. Используйте класс Normalizer2.   -  person Hans Passant    schedule 07.06.2010
comment
И я прошу именно такой фрагмент кода, который использует класс Nornalizer2.   -  person Paul J. Lucas    schedule 08.06.2010


Ответы (2)


ICU позволяет транслитерировать строку, используя определенное правило. Мое правило NFD; [:M:] Remove; NFC: разложить, убрать диакритические знаки, перекомпоновать. Следующий код принимает на входе UTF-8 std::string и возвращает другой UTF-8 std::string:

#include <unicode/utypes.h>
#include <unicode/unistr.h>
#include <unicode/translit.h>

std::string desaxUTF8(const std::string& str) {
    // UTF-8 std::string -> UTF-16 UnicodeString
    UnicodeString source = UnicodeString::fromUTF8(StringPiece(str));

    // Transliterate UTF-16 UnicodeString
    UErrorCode status = U_ZERO_ERROR;
    Transliterator *accentsConverter = Transliterator::createInstance(
        "NFD; [:M:] Remove; NFC", UTRANS_FORWARD, status);
    accentsConverter->transliterate(source);
    // TODO: handle errors with status

    // UTF-16 UnicodeString -> UTF-8 std::string
    std::string result;
    source.toUTF8String(result);

    return result;
}
person Quentin Pradet    schedule 25.10.2012
comment
Очень полезно. Я бы предпочел [: Mn:] вместо [: M:], поскольку последний удаляет знаки гласных в текстах на хинди, которые, как мне кажется, имеют смысл. - person Jyotirmoy Bhattacharya; 20.10.2013
comment
@JyotirmoyBhattacharya Различия, которые делает Unicode, основаны на макете, а не на семантике: это соответствует вашим потребностям в хинди, но в целом не является хорошей идеей. (И диакритические знаки означают значение на многих языках.) Спасибо за ваш комментарий! - person Quentin Pradet; 21.10.2013
comment
Одним из примеров необходимости перекомпоновки является блок Hangul Syllables, U+AC00 - U+D7AF. Все они раскладываются еще на две буквы в блоке Hangul Jamo, U+1100 - U+11FF. Например, U+AC00 разлагается на U+1100 и U+1161, которые, опять же, представляют собой буквы (Lo), а не знаки. - person chx; 16.06.2020
comment
Тот, который указан в unicode-org.github.io/icu/userguide/transforms / general равно NFD; [:Nonspacing Mark:] Remove; NFC - person Alexey Romanov; 21.10.2020

После дополнительных поисков в другом месте:

UErrorCode status = U_ZERO_ERROR;
UnicodeString result;

// 's16' is the UTF-16 string to have diacritics removed
Normalizer::normalize( s16, UNORM_NFKD, 0, result, status );
if ( U_FAILURE( status ) )
  // complain

// code to convert UTF-16 's16' to UTF-8 std::string 's8' elided

string buf8;
buf8.reserve( s8.length() );
for ( string::const_iterator i = s8.begin(); i != s8.end(); ++i ) {
  char const c = *i;
  if ( isascii( c ) )
    buf8.push_back( c );
}
// result is in buf8

что есть O (n).

person Paul J. Lucas    schedule 08.06.2010
comment
Вы не хотите удалять ничего, кроме ASCII, только диакритические знаки. Этот код работает только на нескольких языках. - person Quentin Pradet; 25.10.2012