[英]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如何知道字符串中的“é-€”是日語字符的編碼版本,還是字符é - €和é?
一些說明:
編輯:顯然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.