[英]How to execute a command with multi-byte characters using system function in 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可以接受,您有多種選擇:
MultiByteToWideChar
函數; 不需要額外的依賴。 實際上只有兩種可能的解決方案。 如果你這么做很多,在很遠的距離上,你最好將你的角色轉換為單個元素編碼,使用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很難。
std::wstring
不是代碼點列表,它是wchar_t
的列表,它們的寬度是實現定義的(通常用VC ++為16位,用gcc和clang為32位)。 是的,這意味着它對便攜式代碼毫無用處...... LL
在西班牙語中被認為是一個字母)。 所以...這有點難。
解決3)可能代價高昂(需要特定的語言/使用注釋); 解決1)和2)是絕對必要的......並且需要使用Unicode感知庫或編寫自己的編碼(並且可能會出錯)。
uint32_t
表示) 否則,你可能會在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.