14

質問

C++ (または C) でアクセント付きの文字をすべて通常の文字に変更するにはどうすればよいですか?

つまり、 のようなものeéèêaàäâçcが になるということeeeeaaaaccです。

私がすでに試したこと

文字列を手動で解析し、それぞれを1つずつ置き換えてみましたが、私が知らないより良い/簡単な方法が必要だと考えていました(アクセント付きの文字を忘れないことを保証します) .

標準ライブラリのどこかに既にマップがあるのか​​、それとも数学関数を使用してすべてのアクセント付き文字を「通常の」文字に簡単にマップできるのか疑問に思っています (例: floor(charCode-131/5) + 61))。

4

7 に答える 7

7

私はそれを理論的にしか知りません。基本的には、Unicode の正規化を実行してから分解し、すべての分音記号を削除してから、もう一度再構成します。

于 2012-12-30T21:05:08.097 に答える
7

最初に「アクセント付き文字」の意味を定義する必要があります。128 を超えるコードの国内コードページを使用した拡張 8 ビット ASCII がある場合、または utf8 でエンコードされた文字列がある場合、行う必要があることは大きく異なります。

ただし、Unicode ベースのアクセント付き文字を適切に操作するために必要なものを提供するlibicuを確認する必要があります。

しかし、それですべての問題が解決するわけではありません。たとえば、中国語やロシア語の手紙を受け取ったらどうしますか? ポイントでトルコ語の大文字 I を取得した場合はどうすればよいですか? この「私」のポイントを削除しますか? そうすると、テキストの意味が変わってしまいます...など。この種の問題は、Unicodeでは際限がありません。従来のソート順でも国によって異なります...

于 2012-12-30T22:08:39.730 に答える
2

値が単なる s であると仮定するcharと、目的のターゲット値で配列を作成し、各文字を配列内の対応するメンバーに置き換えるだけです。

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 を使用する場合は、同じ操作を行うために適切なループを作成する必要がありますが、概念的には同じ方法です。同様に、C++ 2011 を使用できない場合は、ラムダ関数の代わりに適切な関数オブジェクトを使用するだけです。

明らかに、replacementアレイは 1 回だけセットアップでき、上記で概説した方法よりもスマートなアプローチを使用できます。ただし、原則は機能するはずです。ただし、Unicode 文字を置き換える必要がある場合は、もう少し興味深いことがあります。たとえば、配列がかなり大きくなり、さらに文字を変更するには複数の単語が必要になる場合があります。

于 2012-12-30T21:15:04.680 に答える
1

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)
  • y <= 2それz = ((y + 1) * 4) + 61以外の場合z = (y * 6) + 61

小文字の場合は、次の手順を実行します。

  • y = floor((x - 224) / 6)
  • y <= 2それz = ((y + 1) * 4) + 93以外の場合z = (y * 6) + 93

最終的な答えzは、必要なアルファベットのASCIIコードです。
この方法は、ISO /IEC8859-1を使用している場合にのみ機能することに注意してください。

于 2012-12-30T21:47:51.967 に答える
1

ここには簡単な方法はありません。

私が取り組んでいるアプリケーションでは、これは内部コードページ テーブルを使用することで解決されました。テーブルは c# を使用して自動生成されました。これには、実際にそれを簡単にするいくつかのクラスが含まれています (実際にはいくつかのヒューリスティックを使用)。

これは、実際にはコードページを持つマルチバイト データ用でしたが、UNICODE 文字列にも使用できます (すべてのテーブルで特定の Unicode 文字を検索するだけです)。

于 2012-12-30T22:23:17.407 に答える
0

私のユース ケースでは、大文字と小文字を区別せずに文字列の長いリストを並べ替える必要がありました。文字列の一部に分音符号が含まれている可能性があります。たとえば、単純な比較で行っていた「Abbeville County」の直前ではなく、「Añasco Municipio」を「Anchorage Municipality」の直前に配置したいと考えました。

私の文字列は UTF-8 でエンコードされていますが、適切な UTF-8 Unicode ではなく、拡張 ASCII 文字が含まれている可能性があります。すべての文字列を UTF-8 に昇格させてから、UTF-8 文字列比較を実行できるライブラリを使用することもできましたが、速度と、発音区別符号を非区別符号文字にどのようにマッピングするかを正確に決定することの両方を完全に制御したかったのです。(私の選択には、男性序数指示子を「o」として扱うことや、著作権文字を c として扱うことなどが含まれます。)

以下の「2 バイト」コードは UTF-8 シーケンスです。「1 バイト」コードは拡張 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's 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;
}
于 2016-07-02T01:50:13.377 に答える