2016-05-23 5 views
5

मैं टर्मिनल आधारित प्रोग्राम पर काम कर रहा हूं जिसमें यूनिकोड समर्थन है। ऐसे कुछ मामले हैं जहां मुझे यह निर्धारित करने की आवश्यकता है कि प्रिंट करने से पहले एक स्ट्रिंग कितनी टर्मिनल कॉलम उपभोग करेगी। दुर्भाग्यवश कुछ पात्र 2 कॉलम चौड़े (चीनी, इत्यादि) हैं, लेकिन मुझे this answer मिला जो आईसीयू लाइब्रेरी से u_getIntPropertyValue() को कॉल करके पूर्णविड्थ वर्णों का पता लगाने का एक अच्छा तरीका इंगित करता है।टर्मिनल में यूनिकोड स्ट्रिंग चौड़ाई का पता लगाने के लिए कैसे?

अब मैं अपने यूटीएफ 8 स्ट्रिंग के पात्रों को पार्स करने और उन्हें इस समारोह में पास करने की कोशिश कर रहा हूं। अब मेरी समस्या यह है कि u_getIntPropertyValue() एक यूटीएफ -32 कोड बिंदु की अपेक्षा करता है।

इसे utf8 स्ट्रिंग से प्राप्त करने का सबसे अच्छा तरीका क्या है? मैं वर्तमान में बूस्ट :: लोकेल (मेरे प्रोग्राम में कहीं और इस्तेमाल किया गया) के साथ ऐसा करने की कोशिश कर रहा हूं, लेकिन मुझे एक साफ रूपांतरण प्राप्त करने में परेशानी हो रही है। बूस्ट ऑर्डर को इंगित करने के लिए बूस्ट :: लोकेल से आने वाले मेरे यूटीएफ 32 तार zero-width character के साथ पूर्व-पेंड किए गए हैं। जाहिर है, मैं सिर्फ स्ट्रिंग के पहले चार बाइट्स को छोड़ सकता हूं, लेकिन क्या ऐसा करने का एक क्लीनर तरीका है?

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; 
} 
+1

आप पहले से ही आईसीयू का उपयोग करते हैं, क्यों UTF8 करने वाली utf32 रूपांतरण के लिए भी इसका इस्तेमाल नहीं? –

+0

मैं आईसीयू से परिचित नहीं हूं। मैं सबसे जटिलता से मुझे अपनाने के लिए बूस्ट :: लोकेल का उपयोग करने की कोशिश कर रहा था। क्या आईसीयू से सीधे यूटीएफ 32 कोड प्राप्त करने का कोई आसान तरीका है? – KyleL

+0

मैं इसके साथ परिचित नहीं हूं लेकिन मुझे पता है कि यह सब कुछ यूनिकोड लाइब्रेरी से कभी भी चाहता था। Google के साथ कुछ समय बिताएं और आपको यह मिल जाएगा। –

उत्तर

1

UTF-32 अलग-अलग पात्रों के "कोड अंक" के प्रत्यक्ष प्रतिनिधित्व है। तो आपको बस इतना करना है कि वे यूटीएफ -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; 
} 
+0

बढ़ावा कार्यान्वयन के लिए धन्यवाद। दिलचस्प है कि यह रेगेक्स लाइब्रेरी का हिस्सा है और लोकेल नहीं है। – KyleL

2

@ n.m सही था: वहाँ एक आसान तरीका आईसीएस के साथ सीधे यह करने के लिए है

यहाँ मेरे वर्तमान बदसूरत समाधान है। अद्यतन कोड नीचे है। मुझे संदेह है कि मैं शायद यूनिकोडस्ट्रिंग का उपयोग कर सकता हूं और इस परिदृश्य में पूरे बूस्ट लोकेल उपयोग को बाईपास कर सकता हूं।

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; 
} 
+1

शून्य-चौड़ाई वाले वर्णों को भी संभालना न भूलें! – o11c

+0

@ o11c क्या आप जानते हैं कि इसे कैसे जांचें? मैं अपनी संभवतः गुमराह Google खोज के साथ रिक्त स्थान बदल रहा हूं। – KyleL

+0

{"एमएन", "मी"} या Default_Ignorable_Code_Point' में 'सामान्य_Category' जैसा कुछ है - बाद में स्वरूपण वर्ण, मुलायम हाइफ़न इत्यादि शामिल हैं लेकिन फिर, आपको हंगुल संयोजन के लिए और भी जटिल सामग्री करना है, जो इस पर निर्भर करता है पिछले चरित्र था। – o11c

संबंधित मुद्दे