2016-02-11 2 views
6

मेरे पास std :: स्ट्रिंग में एक मान्य utf-8 एन्कोडेड स्ट्रिंग है। मेरे पास बाइट्स में सीमा है। मैं स्ट्रिंग को छोटा करना और जोड़ना चाहता हूं ... MAX_SIZE - 3 - x पर - जहां x वह मान है जो एक utf-8 वर्ण को काटने से रोक देगा।std :: सुरक्षित स्थान पर utf-8 को छोटा करने के लिए स्ट्रिंग इष्टतम तरीका

क्या कोई ऐसा कार्य है जो स्ट्रिंग की शुरुआत से शुरू होने की आवश्यकता के बिना MAX_SIZE पर आधारित x निर्धारित कर सकता है?

उत्तर

11

यदि आपके पास स्ट्रिंग में कोई स्थान है, और आप यूटीएफ -8 वर्ण (और इसलिए कट करने के लिए एक वैध स्थान) की शुरुआत को खोजने के लिए पीछे की ओर जाना चाहते हैं, तो यह काफी आसानी से किया जाता है।

आप अनुक्रम में अंतिम बाइट से शुरू करते हैं। यदि अंतिम बाइट के शीर्ष दो बिट 10 हैं, तो यह यूटीएफ -8 अनुक्रम का हिस्सा है, इसलिए शीर्ष दो बिट्स 10 (या जब तक आप शुरुआत तक नहीं पहुंच जाते) तक बैक अप रखें।

यूटीएफ -8 काम करता है कि बाइट के ऊपरी बिट्स के आधार पर बाइट तीन चीजों में से एक हो सकता है। यदि सबसे ऊपर बिट 0 है, तो बाइट एक ASCII चरित्र है, और अगले 7 बिट्स यूनिकोड कोडपॉइंट मान हैं। यदि सबसे ऊपर बिट 10 है, तो 6 बिट्स जो अनुवर्ती हैं वे बहु-बाइट अनुक्रम के लिए अतिरिक्त बिट्स हैं। लेकिन मल्टीबाइट अनुक्रम के को शीर्ष बिट्स में 11 के साथ कोड किया गया है (और अनुक्रम में बाइट्स की संख्या निर्धारित है कि 1 एस पहले 0 से पहले उन दोनों का पालन करें)।

तो यदि बाइट की शीर्ष बिट्स 10 नहीं हैं, तो यह या तो एक ASCII वर्ण या मल्टीबाइट अनुक्रम की शुरुआत है। किसी भी तरह से, यह कटौती करने के लिए एक वैध जगह है।

नोट हालांकि, यह कोडपॉइंट सीमाओं पर स्ट्रिंग को तोड़ देगा, यह यूनिकोड ग्रैफेम क्लस्टर पर आधारित है। इसका मतलब यह है कि पात्रों को संयोजित किया जा सकता है, जो उन मूल पात्रों से दूर हो जाते हैं जिन्हें वे गठबंधन करते हैं; उदाहरण के लिए, अक्षरों से उच्चारण खो सकते हैं। उचित ग्रैफेम क्लस्टर विश्लेषण करने के लिए यूनिकोड तालिका तक पहुंच की आवश्यकता होगी जो कहता है कि कोई कोडपॉइंट एक संयोजन चरित्र है या नहीं।

लेकिन यह कम से कम एक वैध यूनिकोड यूटीएफ -8 स्ट्रिंग होगा। ताकि बेहतर ज्यादातर लोगों करते हैं;)


कोड कुछ इस तरह दिखेगा (सी ++ 14 में):

auto FindCutPosition(const std::string &str, size_t max_size) 
{ 
    assert(str.size() >= max_size, "Make sure stupidity hasn't happened."); 
    assert(str.size() > 3, "Make sure stupidity hasn't happened."); 
    max_size -= 3; 
    for(size_t pos = max_size; pos > 0; --pos) 
    { 
    unsigned char byte = static_cast<unsigned char>(str[pos]); //Perfectly valid 
    if(byte & 0xC0 != 0x80) 
     return pos; 
    } 

    unsigned char byte = static_cast<unsigned char>(str[0]); //Perfectly valid 
    if(byte & 0xC0 != 0x80) 
    return 0; 

    //If your first byte isn't even a valid UTF-8 starting point, then something terrible has happened. 
    throw bad_utf8_encoded_text(...); 
} 
+0

वास्तव में, UTF-8 एन्कोडिंग की बाइट पैटर्न इस तरह कर रहे हैं, कि अगला चरित्र शुरू होने वाली सीमा निर्धारित करने के लिए यह संभवतः संभव है। –

+0

मुझे डेटा पता है - मैं सिर्फ भिखारी से पुनरावृत्ति नहीं करना चाहता हूं, यह पता लगाने के लिए कि कौन सा/छोटा है – gsf

+0

प्रश्न यह है कि मैं यह निर्धारित कर सकता हूं कि मैं कहां से शुरू होता हूं। – gsf

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