我正在开发一个基于terminal的程序,它支持Unicode。 在某些情况下,我需要确定一个string在打印之前会消耗多lessterminal列。 不幸的是,有些字符是2列(中文等),但我发现这个答案 ,表明检测全angular字符的一个好方法是通过调用ICU库中的u_getIntPropertyValue()。
现在我试图parsing我的UTF8string的字符,并将它们传递给此函数。 我现在遇到的问题是,u_getIntPropertyValue()需要一个UTF-32代码点。
什么是从utf8string获得这个最好的方法? 我目前正在尝试使用boost :: locale(在我的程序中的其他地方使用),但是我无法获得干净的转换。 来自boost :: locale的我的UTF32string被预先填充了一个零宽度字符来表示字节顺序。 显然,我可以跳过string的前四个字节,但有没有更干净的方法来做到这一点?
这是我目前丑陋的解决scheme:
inline size_t utf8PrintableSize(const std::string &str, std::locale loc) { namespace ba = boost::locale::boundary; ba::ssegment_index map(ba::character, str.begin(), str.end(), loc); size_t widthCount = 0; for (ba::ssegment_index::iterator it = map.begin(); it != map.end(); ++it) { ++widthCount; std::string utf32Char = boost::locale::conv::from_utf(it->str(), std::string("utf-32")); UChar32 utf32Codepoint = 0; memcpy(&utf32Codepoint, utf32Char.c_str()+4, sizeof(UChar32)); int width = u_getIntPropertyValue(utf32Codepoint, UCHAR_EAST_ASIAN_WIDTH); if ((width == U_EA_FULLWIDTH) || (width == U_EA_WIDE)) { ++widthCount; } } return widthCount; }
UTF-32是单个字符的“代码点”的直接表示。 因此,您只需从UTF-8字符中提取这些字符,并将其提供给u_getIntPropertyValue
。
我把你的代码和修改它使用u8_to_u32_iterator ,这似乎只是为了这个:
#include <boost/regex/pending/unicode_iterator.hpp> inline size_t utf8PrintableSize(const std::string &str, std::locale loc) { size_t widthCount = 0; for(boost::u8_to_u32_iterator<std::string::iterator> it(input.begin()), end(input.end()); it!=end; ++it) { ++widthCount; int width = u_getIntPropertyValue(*it, UCHAR_EAST_ASIAN_WIDTH); if ((width == U_EA_FULLWIDTH) || (width == U_EA_WIDE)) { ++widthCount; } } return widthCount; }
@ nm是正确的:有一个简单的方法来直接与ICS做到这一点。 更新的代码如下。 我怀疑我可以只使用UnicodeString,并绕过整个提升区域使用情况。
inline size_t utf8PrintableSize(const std::string &str, std::locale loc) { namespace ba = boost::locale::boundary; ba::ssegment_index map(ba::character, str.begin(), str.end(), loc); size_t widthCount = 0; for (ba::ssegment_index::iterator it = map.begin(); it != map.end(); ++it) { ++widthCount; //Note: Some unicode characters are 'full width' and consume more than one // column on output. We will increment widthCount one extra time for // these characters to ensure that space is properly allocated UnicodeString ucs = UnicodeString::fromUTF8(StringPiece(it->str())); UChar32 codePoint = ucs.char32At(0); int width = u_getIntPropertyValue(codePoint, UCHAR_EAST_ASIAN_WIDTH); if ((width == U_EA_FULLWIDTH) || (width == U_EA_WIDE)) { ++widthCount; } } return widthCount; }