【问题标题】:Code to strip diacritical marks using ICU使用 ICU 去除变音符号的代码
【发布时间】:2010-06-07 18:24:22
【问题描述】:

有人可以提供一些示例代码来去除变音符号(即,将具有重音、变音符号等的字符替换为未重音、未变音等的字符等价物,例如,每个重音 é 都会变成普通的ASCII e) 来自 UnicodeString 使用 C++ 中的 ICU 库?例如:

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

假设s 已经被标准化。谢谢。

【问题讨论】:

  • 这个问题和任何给定的答案都没有使用 ICU 库。
  • 那又怎样?基本步骤是分解字符串,然后过滤掉变音符号。使用 Normalizer2 类。
  • 我要求的正是这样一个“使用 Nornalizer2 类”的代码 sn-p。

标签: c++ unicode diacritics icu


【解决方案1】:

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

【讨论】:

  • 非常有用。我更喜欢 [:Mn:] 而不是 [:M:] 因为后者删除了印地语文本中的元音标记,我认为这是有意义的。
  • @JyotirmoyBhattacharya Unicode 的区别是基于布局,而不是语义:这适合您对印地语的需求,但总体上不是一个好主意。 (而且变音符号在许多语言中都具有意义。)感谢您的评论!
  • 一个需要重构的例子是韩文音节块,U+AC00 - U+D7AF。在 Hangul Jamo,U+1100 - U+11FF 块中,它们都分解成另外两个字母。例如,U+AC00 分解为 U+1100U+1161,它们又是字母 (Lo) 而不是标记。
  • unicode-org.github.io/icu/userguide/transforms/general 中给出的是NFD; [:Nonspacing Mark:] Remove; NFC
【解决方案2】:

在其他地方进行更多搜索后:

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)。

【讨论】:

  • 你不想删除任何非 ASCII 的东西,只是变音符号。此代码仅适用于几种语言。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
  • 2012-01-01
  • 1970-01-01
  • 2014-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多