簡體   English   中英

C ++子串多字節字符

[英]C++ substring multi byte characters

我有這個std :: string,其中包含一些跨越多個字節的字符。

當我對此字符串執行子字符串時,輸出無效,因為當然,這些字符計為2個字符。 在我看來,我應該使用wstring,因為它將這些字符存儲為一個元素而不是更多。

所以我決定將字符串復制到wstring中,但是當然這沒有意義,因為字符仍然分為2個字符。 這只會讓情況變得更糟。

將字符串轉換為wstring有一個很好的解決方案,將特殊字符合並為1個元素而不是2個元素。

謝謝

更簡單的版本。 基於提供的解決方案獲取UTF-8編碼的std :: string的實際長度? 作者Marcelo Cantos

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

std::string對象不是字符串,而是一串字節。 它根本沒有所謂的“ 編碼 ”的概念。 同樣適用於std::wstring ,除了它是一個16位值的字符串。

為了對需要處理不同字符的文本執行操作(例如,當您想要獲取子字符串時),您需要知道std :: string對象使用的編碼。

更新:現在你明確了你的輸入字符串是UTF-8編碼的,你仍然需要決定用於輸出std::wstring的編碼。 我想到了UTF-16,但它實際上取決於您將傳遞std::wstring對象的API所期望的內容。 假設UTF-16可以接受,您有多種選擇:

  1. 在Windows上,您可以使用MultiByteToWideChar函數; 不需要額外的依賴。
  2. UTF8-CPP庫聲稱提供了一種輕量級的解決方案來處理UTF- *編碼的字符串。 從來沒有嘗試過,但我一直聽到它的好消息。
  3. 在Linux系統上,使用libiconv庫非常常見。
  4. 如果你需要處理各種瘋狂的編碼,並且想要編碼完整的alpha-and-omega字,請看ICU

實際上只有兩種可能的解決方案。 如果你這么做很多,在很遠的距離上,你最好將你的角色轉換為單個元素編碼,使用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 ;
}

Unicode很難。

  1. std::wstring不是代碼點列表,它是wchar_t的列表,它們的寬度是實現定義的(通常用VC ++為16位,用gcc和clang為32位)。 是的,這意味着它對便攜式代碼毫無用處......
  2. 單個字符可能在幾個代碼點上編碼(由於變音符號
  3. 在某種語言中,兩個不同的字符一起形成一個不可分離的“單元”(例如, LL在西班牙語中被認為是一個字母)。

所以...這有點難。

解決3)可能代價高昂(需要特定的語言/使用注釋); 解決1)和2)是絕對必要的......並且需要使用Unicode感知庫或編寫自己的編碼(並且可能會出錯)。

  • 1)簡單解決:編寫從UTF-8轉換到CodePoint的例程是微不足道的(CodePoint可以用uint32_t表示)
  • 2)更難,它需要一個變音符列表,子程序必須知道在變音之前永遠不要削減(他們遵循他們的資格)

否則,你可能會在ICU找到什么。 祝你好運,找到它。

讓我假設您的編碼是UTF-8。 在這種情況下,我們會有一些字符占用多個字節,就像你的情況一樣。 然后你有std :: string,其中存儲了那些UTF-8編碼的字符。 現在你想用chars而不是字節來表示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個字符串中刪除字符串()。 沒問題:

int32 pos = GetByteCountForCharCount(str.c_str(), 7);
str.substr(pos); 

基於此,我編寫了我的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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM