4

私はこのstd::stringを持っていますが、これには複数のバイトにまたがるいくつかの文字が含まれています。

この文字列に対して部分文字列を実行すると、出力は無効になります。もちろん、これらの文字は2文字としてカウントされます。私の意見では、代わりにwstringを使用する必要があります。これは、これらの文字を複数ではなく1つの要素として格納するためです。

そこで、文字列をwstringにコピーすることにしましたが、文字が2文字に分割されたままであるため、もちろんこれは意味がありません。これはそれを悪化させるだけです。

文字列をwstringに変換し、特殊文字を2つではなく1つの要素にマージする良い解決策はありますか?

ありがとう

4

6 に答える 6

7

よりシンプルなバージョン。提供されたソリューションに基づくUTF-8でエンコードされたstd::stringの実際の長さを取得しますか?マルセロ・カントス

std::string substr(std::string originalString, int maxLength)
{
    std::string resultString = originalString;

    int len = 0;
    int byteCount = 0;

    const char* aStr = originalString.c_str();

    while(*aStr)
    {
        if( (*aStr & 0xc0) != 0x80 )
            len += 1;

        if(len>maxLength)
        {
            resultString = resultString.substr(0, byteCount);
            break;
        }
        byteCount++;
        aStr++;
    }

    return resultString;
}
于 2012-08-14T06:37:30.390 に答える
5

オブジェクトは文字std::string列ではなく、バイト文字列です。いわゆる「エンコーディング」の概念はまったくありません。std::wstring16ビット値の文字列であることを除いて、同じことが当てはまります。

個別の文字をアドレス指定する必要があるテキストに対して操作を実行するには(たとえば、部分文字列を取得する場合のように)、std::stringオブジェクトに使用されているエンコーディングを知る必要があります。

更新:入力文字列がUTF-8でエンコードされていることを明確にしたので、出力に使用するエンコードを決定する必要がありますstd::wstringstd::wstringUTF-16が思い浮かびますが、それは実際には、オブジェクトに渡すAPIが何であるかによって異なります。UTF-16が受け入れ可能であると仮定すると、さまざまな選択肢があります。

  1. MultiByteToWideCharWindowsでは、この関数を使用できます。追加の依存関係は必要ありません。
  2. UTF8-CPPライブラリは、UTF-*でエンコードされた文字列を処理するための軽量ソリューションを提供すると主張しています。自分で試したことはありませんが、良いことを聞き続けています。
  3. Linuxシステムでは、libiconvライブラリを使用するのが非常に一般的です。
  4. あらゆる種類のクレイジーなエンコーディングを処理する必要があり、エンコーディングに関する限り本格的なアルファおよびオメガワードが必要な場合は、ICUを参照してください。
于 2012-06-01T08:38:31.660 に答える
1

考えられる解決策は実際には2つだけです。wchar_tこれを長距離で頻繁に行う場合は、 (またはint32_t、または、または最も適切なものを使用して、文字を単一の要素エンコーディングに変換することをお勧めします。これは、各個人を変換する単純なコピーではありませんchar。ターゲットタイプに変換しますが、マルチバイト文字を認識して単一の要素に変換する真の変換関数です。

nたまに使用したり、シーケンスを短くしたりする場合は、バイトを進めるための独自の関数を作成することができます。UTF-8の場合、次を使用します。

inline size_t
size(
    Byte                ch )
{
    return byteCountTable[ ch ] ;
}

template< typename InputIterator >
InputIterator
succ(
    InputIterator       begin,
    size_t              size,
    std::random_access_iterator_tag )
{
    return begin + size ;
}

template< typename InputIterator >
InputIterator
succ(
    InputIterator       begin,
    size_t              size,
    std::input_iterator_tag )
{
    while ( size != 0 ) {
        ++ begin ;
        -- size ;
    }
    return begin ;
}

template< typename InputIterator >
InputIterator
succ(
    InputIterator       begin,
    InputIterator       end )
{
    if ( begin != end ) {
        begin = succ( begin, end, size( *begin ),
                      std::::iterator_traits< InputIterator >::iterator_category() ) ;
    }
    return begin ;
}

template< typename InputIterator >
size_t
characterCount(
    InputIterator       begin,
    InputIterator       end )
{
    size_t              result = 0 ;
    while ( begin != end ) {
        ++ result ;
        begin = succ( begin, end ) ;
    }
    return result ;
}
于 2012-06-01T09:53:06.653 に答える
1

Unicodeは難しいです。

  1. std::wstringはコードポイントのリストではなく、のリストでありwchar_t、その幅は実装によって定義されます(通常、VC ++では16ビット、gccとclangでは32ビット)。はい、それはポータブルコードには役に立たないことを意味します...
  2. 1つの文字が複数のコードポイントでエンコードされる場合があります(発音区別符号のため)
  3. 一部の言語では、2つの異なる文字が一緒になって、実際には分離できない「単位」を形成します(たとえば、LLスペイン語ではそれ自体が文字と見なされます)。

だから...それは少し難しいです。

3)解決にはコストがかかる可能性があります(特定の言語/使用法の注釈が必要です)。1)と2)を解決することは絶対に必要です...そしてUnicode対応のライブラリまたは独自のコーディングが必要です(そしておそらくそれを間違えます)。

  • 1)簡単に解決できます:UTF-8からCodePointに変換するルーチンを作成するのは簡単です(CodePointはuint32_t)で表すことができます
  • 2)より難しく、発音区別符号のリストが必要であり、サブルーチンは発音区別符号の前に決して切り取らないことを知っている必要があります(彼らは資格のある文字に従います)

そうでなければ、おそらくあなたがICUに求めるものがあります。幸運を祈ります。

于 2012-06-01T11:38:24.647 に答える
0

簡単にするために、エンコーディングはUTF-8であると仮定します。この場合、あなたの場合のように、いくつかの文字が複数のバイトを占有します。次に、std :: stringがあり、UTF-8でエンコードされた文字が格納されます。そして今、あなたはバイトではなく文字の観点からsubstr()をしたいと思っています。文字長をバイト長に変換する関数を書きます。utf 8の場合、次のようになります。

#define UTF8_CHAR_LEN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1

int32 GetByteCountForCharCount(const char* utf8Str, int charCnt)
{
    int ByteCount = 0;
    for (int i = 0; i < charCnt; i++)
    {
        int charlen = UTF8_CHAR_LEN(*utf8Str);
        ByteCount += charlen;
        utf8Str += charlen;
    }
    return ByteCount;
}

したがって、7番目の文字からの文字列をsubstr()したいとします。問題ない:

int32 pos = GetByteCountForCharCount(str.c_str(), 7);
str.substr(pos); 
于 2012-06-01T09:04:33.277 に答える
0

これに基づいて、utf8サブストリング関数を作成しました。

void utf8substr(std::string originalString, int SubStrLength, std::string& csSubstring)
{
    int len = 0, byteIndex = 0;
    const char* aStr = originalString.c_str();
    size_t origSize = originalString.size();

    for (byteIndex=0; byteIndex < origSize; byteIndex++)
    {
        if((aStr[byteIndex] & 0xc0) != 0x80)
            len += 1;

        if(len >= SubStrLength)
            break;
    }

    csSubstring = originalString.substr(0, byteIndex);
}
于 2016-01-22T06:55:58.020 に答える