簡體   English   中英

如何正確使用Windows API中的CharNext?

[英]How do I use CharNext in the Windows API properly?

我有一個包含日語和拉丁字符混合的多字節字符串。 我正在嘗試將此字符串的一部分復制到單獨的內存位置。 由於它是一個多字節字符串,因此某些字符使用一個字節而其他字符使用兩個字符。 復制字符串的部分時,我不能復制“半”日文字符。 為了能夠正確地執行此操作,我需要能夠確定多字節字符串字符的開始和結束位置。

例如,如果字符串包含需要[2字節] [2字節] [1字節]的3個字符,我必須將2個,4個或5個字節復制到另一個位置而不是3個,因為如果我復制3個I只復制第二個字符的一半。

要弄清楚多字節字符串字符的開始和結束位置,我正在嘗試使用Windows API函數CharNext和CharNextExA,但沒有運氣。 當我使用這些函數時,它們一次一個字節地導航我的字符串,而不是一次一個字符。 根據MSDN,CharNext應該是CharNext函數檢索指向字符串中下一個字符的指針。

這里有一些代碼來說明這個問題:

#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>

/* string consisting of six "asian" characters */
wchar_t wcsString[] = L"\u9580\u961c\u9640\u963f\u963b\u9644";

int main() 
{
   // Convert the asian string from wide char to multi-byte.
   LPSTR mbString = new char[1000];
   WideCharToMultiByte( CP_UTF8, 0, wcsString, -1, mbString, 100,  NULL, NULL);

   // Count the number of characters in the string.
   int characterCount = 0;
   LPSTR currentCharacter = mbString;
   while (*currentCharacter)
   {
      characterCount++;

     currentCharacter = CharNextExA(CP_UTF8, currentCharacter, 0);
   }
}

(請忽略內存泄漏和無法進行錯誤檢查。)

現在,在上面的例子中,我希望characterCount變為6,因為這是亞洲字符串中的字符數。 但是,相反,characterCount變為18,因為mbString包含18個字符:

門阜陀阿阻附

我不明白它應該如何工作。 CharNext如何知道字符串中的“é-€”是日語字符的編碼版本,還是字符é - €和é?

一些說明:

  • 我已經閱讀了Joels博客文章,了解每個開發人員需要了解的有關Unicode的信息。 雖然我可能誤解了一些東西。
  • 如果我想做的就是計算字符數,我可以直接計算亞洲字符串中的字符數。 請記住,我的真正目標是將多字節字符串的一部分復制到一個單獨的位置。 單獨的位置僅支持多字節,而不支持widechar。
  • 如果我使用MultiByteToWideChar將mbString的內容轉換回寬字符,我得到正確的字符串(門阜陀阿阻附),這表明mbString沒有任何問題。

編輯:顯然CharNext函數不支持UTF-8但微軟忘記記錄。 我扔了/復制了我自己的例程,我不會使用它,需要改進。 我猜它很容易被撞壞。

  LPSTR CharMoveNext(LPSTR szString)
  {
     if (szString == 0 || *szString == 0)
        return 0;

     if ( (szString[0] & 0x80) == 0x00)
        return szString + 1;
     else if ( (szString[0] & 0xE0) == 0xC0)
        return szString + 2;
     else if ( (szString[0] & 0xF0) == 0xE0)
        return szString + 3;
     else if ( (szString[0] & 0xF8) == 0xF0)
        return szString + 4;
     else
        return szString +1;
  }

以下是對Sorting it All Out博客中發生的事情的一個非常好的解釋: CharNextExA是否已損壞? 簡而言之,CharNext不適用於UTF8字符串。

據我所知(google和實驗), CharNextExA實際上並不適用於UTF-8,只支持使用較短的前導/尾部字節對或單字節字符的多字節編碼。

UTF-8是一種相當規則的編碼,有很多庫可以做你想要的,但也可以很容易地自己編寫。

在這里查看unicode.org ,特別是有關序列表格的表3-7。

const char* NextUtf8( const char* in )
{
    if( in == NULL || *in == '\0' )
        return in;

    unsigned char uc = static_cast<unsigned char>(*in);

    if( uc < 0x80 )
    {
        return in + 1;
    }
    else if( uc < 0xc2 )
    {
         // throw error? invalid lead byte
    }
    else if( uc < 0xe0 )
    {
        // check in[1] for validity( 0x80 .. 0xBF )
        return in + 2;
    }
    else if( uc < 0xe1 )
    {
        // check in[1] for validity( 0xA0 .. 0xBF )
        // check in[2] for validity( 0x80 .. 0xBF )
        return in + 3;
    }
    else // ... etc.
    // ...
}

鑒於CharNextExA不能與UTF-8一起使用 ,您可以自己解析它。 只需跳過前兩位中有10個字符的字符。 您可以在UTF-8的定義中看到模式: http//en.wikipedia.org/wiki/Utf-8

LPSTR CharMoveNext(LPSTR szString)
{
    ++szString;
    while ((*szString & 0xc0) == 0x80)
        ++szString;
    return szString;
}

這不是您問題的直接答案,但您可能會發現以下教程很有幫助,我當然也這樣做了。 事實上,這里提供的信息足以讓您輕松地自己遍歷多字節字符串:

完整的字符串教程

嘗試使用932代碼頁。 我不認為CP_UTF8是真正的代碼頁,它可能只適用於WideCharToMultibyte()和返回。 您也可以嘗試使用isleadByte(),但這需要正確設置區域設置或正確設置默認代碼頁。 我已經成功使用了IsDBCSLeadByteEx(),但從未使用過CP_UTF8。

暫無
暫無

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

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