我想迭代 Unicode字符串的每个字符,处理每个代理对并将字符序列组合为一个单元(一个字母)。
文本“नमस्ते”由代码点组成:U+0928, U+092E, U+0938, U+094D, U+0924, U+0947
,其中U+0938
和U+0947
组合标记。
static void Main(string[] args)
{
const string s = "नमस्ते";
Console.WriteLine(s.Length); // Ouptuts "6"
var l = 0;
var e = System.Globalization.StringInfo.GetTextElementEnumerator(s);
while(e.MoveNext()) l++;
Console.WriteLine(l); // Outputs "4"
}
所以我们在.NET中有它。我们还有Win32的CharNextW()
#include <Windows.h>
#include <iostream>
#include <string>
int main()
{
const wchar_t * s = L"नमस्ते";
std::cout << std::wstring(s).length() << std::endl; // Gives "6"
int l = 0;
while(CharNextW(s) != s)
{
s = CharNextW(s);
++l;
}
std::cout << l << std::endl; // Gives "4"
return 0;
}
我所知道的两种方式都是微软特有的。有便携式方法吗?
UnicodeString(s).length()
仍然给出了6)。指向ICU中的相关功能/模块是一个可以接受的答案。 @McDowell给出了使用来自ICU的BreakIterator
的提示,我认为这可以被视为处理Unicode的事实上的跨平台标准。这是一个示例代码来演示它的用法(因为示例令人惊讶罕见):
#include <unicode/schriter.h>
#include <unicode/brkiter.h>
#include <iostream>
#include <cassert>
#include <memory>
int main()
{
const UnicodeString str(L"नमस्ते");
{
// StringCharacterIterator doesn't seem to recognize graphemes
StringCharacterIterator iter(str);
int count = 0;
while(iter.hasNext())
{
++count;
iter.next();
}
std::cout << count << std::endl; // Gives "6"
}
{
// BreakIterator works!!
UErrorCode err = U_ZERO_ERROR;
std::unique_ptr<BreakIterator> iter(
BreakIterator::createCharacterInstance(Locale::getDefault(), err));
assert(U_SUCCESS(err));
iter->setText(str);
int count = 0;
while(iter->next() != BreakIterator::DONE) ++count;
std::cout << count << std::endl; // Gives "4"
}
return 0;
}
答案 0 :(得分:13)
你应该能够使用ICU BreakIterator(假设它的特征等同于Java版本的字符实例)。
答案 1 :(得分:2)
如果使用utf-8对你来说,Glib的ustring类会给你utf-8字符串。它的设计类似于std::string
。由于utf-8是Linux原生的,因此您的任务非常简单:
int main()
{
Glib::ustring s = L"नमस्ते";
cout << s.size();
}
您也可以像往常一样使用Glib::ustring::iterator
答案 2 :(得分:0)
ICU有一个非常古老的界面,Boost.Locale要好得多:
#include <iostream>
#include <string_view>
#include <boost/locale.hpp>
using namespace std::string_view_literals;
int main()
{
boost::locale::generator gen;
auto string = "noël "sv;
boost::locale::boundary::csegment_index map{
boost::locale::boundary::character, std::begin(string),
std::end(string), gen("")};
for (const auto& i : map)
{
std::cout << i << '\n';
}
}
文字来自here