मैंने पढ़ा है और सुना है कि C ++ 11 यूनिकोड का समर्थन करता है। उस पर कुछ सवाल:
- C ++ मानक पुस्तकालय यूनिकोड का कितना अच्छा समर्थन करता है?
- क्या
std::string
यह क्या करना चाहिए? - मैं इसे कैसे इस्तेमाल करूं?
- संभावित समस्याएं कहां हैं?
मैंने पढ़ा है और सुना है कि C ++ 11 यूनिकोड का समर्थन करता है। उस पर कुछ सवाल:
std::string
यह क्या करना चाहिए?जवाबों:
C ++ मानक पुस्तकालय यूनिकोड का कितना अच्छा समर्थन करता है?
बहुत।
पुस्तकालय सुविधाओं के माध्यम से एक त्वरित स्कैन जो यूनिकोड समर्थन प्रदान कर सकता है, मुझे यह सूची प्रदान करता है:
मुझे लगता है कि सभी पहले एक भयानक समर्थन प्रदान करते हैं। मैं आपके अन्य प्रश्नों के माध्यम से त्वरित चक्कर लगाने के बाद इसे और अधिक विस्तार से प्राप्त करूंगा।
क्या
std::string
यह क्या करना चाहिए?
हाँ। C ++ मानक के अनुसार, यह वही है जो std::string
उसके भाई-बहनों को करना चाहिए:
वर्ग टेम्पलेट
basic_string
उन वस्तुओं का वर्णन करता है जो किसी अनुक्रम को स्टोर कर सकते हैं जिसमें स्थिति शून्य के अनुक्रम के पहले तत्व के साथ मनमाने ढंग से चार-समान वस्तुओं की एक अलग संख्या शामिल है।
खैर, std::string
क्या यह ठीक है। क्या यह कोई यूनिकोड-विशिष्ट कार्यक्षमता प्रदान करता है? नहीं।
इसे होना चाहिए? शायद ऩही। वस्तुओं के std::string
अनुक्रम के रूप में ठीक है char
। यह उपयोगी है; केवल झुंझलाहट यह है कि यह पाठ का एक बहुत ही निम्न-स्तरीय दृश्य है और मानक C ++ एक उच्च-स्तरीय एक प्रदान नहीं करता है।
मैं इसे कैसे इस्तेमाल करूं?
char
वस्तुओं के अनुक्रम के रूप में इसका उपयोग करें ; यह दिखावा कुछ और है जो दर्द में समाप्त होता है।
संभावित समस्याएं कहां हैं?
सभी जगह? चलो देखते हैं...
स्ट्रींग लाइब्रेरी
स्ट्रिंग्स लाइब्रेरी हमें प्रदान करती है basic_string
, जो केवल इस बात का एक क्रम है कि मानक "चार्-लाइक ऑब्जेक्ट्स" को क्या कहते हैं। मैं उन्हें कोड इकाइयाँ कहता हूँ। यदि आप पाठ का उच्च-स्तरीय दृश्य चाहते हैं, तो यह वह नहीं है जो आप खोज रहे हैं। यह क्रमांकन / deserialization / भंडारण के लिए उपयुक्त पाठ का एक दृश्य है।
यह सी लाइब्रेरी से कुछ उपकरण भी प्रदान करता है जिनका उपयोग संकीर्ण दुनिया और यूनिकोड दुनिया के बीच की खाई को पाटने के लिए किया जा सकता है: c16rtomb
/ mbrtoc16
और c32rtomb
/ mbrtoc32
।
स्थानीयकरण पुस्तकालय
स्थानीयकरण पुस्तकालय अभी भी मानता है कि उन "चार जैसी वस्तुओं" में से एक "चरित्र" के बराबर है। यह निश्चित रूप से मूर्खतापूर्ण है, और एएससीआईआई जैसे यूनिकोड के कुछ छोटे सबसेट से परे बहुत सारी चीजें ठीक से काम करना असंभव बनाता है।
उदाहरण के लिए, <locale>
हेडर में मानक "सुविधा इंटरफेस" को क्या कहते हैं :
template <class charT> bool isspace (charT c, const locale& loc);
template <class charT> bool isprint (charT c, const locale& loc);
template <class charT> bool iscntrl (charT c, const locale& loc);
// ...
template <class charT> charT toupper(charT c, const locale& loc);
template <class charT> charT tolower(charT c, const locale& loc);
// ...
कैसे आप इन कार्यों के किसी भी ठीक से वर्गीकृत, कहते हैं, U + 1F34C ʙᴀɴᴀɴᴀ की उम्मीद करते हैं, के रूप में u8"🍌"
या u8"\U0001F34C"
? इसका कोई तरीका नहीं है कि यह कभी भी काम करेगा, क्योंकि ये फ़ंक्शन इनपुट के रूप में केवल एक कोड इकाई लेते हैं।
यह उपयुक्त लोकेल के साथ काम कर सकता है यदि आपने char32_t
केवल उपयोग किया है : U'\U0001F34C'
UTF-32 में एक एकल कोड इकाई है।
हालाँकि, इसका मतलब यह है कि आप केवल सरल आवरण परिवर्तन प्राप्त कर सकते हैं toupper
और tolower
, उदाहरण के लिए, जो कुछ जर्मन स्थानों के लिए पर्याप्त नहीं हैं: "pp" अपरकेस से "SS" you लेकिन toupper
केवल एक वर्ण कोड इकाई वापस कर सकते हैं ।
अगला, wstring_convert
/ wbuffer_convert
और मानक कोड रूपांतरण पहलू।
wstring_convert
किसी दिए गए एन्कोडिंग में स्ट्रिंग्स को दूसरे दिए गए एन्कोडिंग में स्ट्रिंग्स के बीच बदलने के लिए उपयोग किया जाता है। इस परिवर्तन में दो स्ट्रिंग प्रकार शामिल हैं, जो मानक एक बाइट स्ट्रिंग और एक विस्तृत स्ट्रिंग कहते हैं। चूंकि ये शब्द वास्तव में भ्रामक हैं, इसलिए मैं † के बजाय क्रमशः "क्रमबद्ध" और "deserialized" का उपयोग करना पसंद करता हूं।
के बीच कनवर्ट करने के लिए एन्कोडिंग एक codecvt (एक कोड रूपांतरण पहलू) द्वारा तय कर रहे हैं एक टेम्पलेट प्रकार तर्क के रूप में पारित कर दिया wstring_convert
।
wbuffer_convert
एक समान कार्य करता है लेकिन एक विस्तृत deserialized स्ट्रीम बफ़र के रूप में जो बाइट क्रमबद्ध स्ट्रीम बफ़र को लपेटता है । किसी भी I / O को अंतर्निहित बाइट क्रमबद्ध स्ट्रीम बफर के माध्यम से किया जाता है और कोडकवेट तर्क द्वारा दिए गए एन्कोडिंग से रूपांतरण के साथ। लेखन उस बफ़र में क्रमबद्ध करता है, और फिर उसमें से लिखता है, और पठन बफ़र में पढ़ता है और फिर इससे डिस्क्राइब होता है।
मानक इन सुविधाओं के साथ उपयोग के लिए कुछ codecvt वर्ग टेम्पलेट्स प्रदान करता है: codecvt_utf8
, codecvt_utf16
, codecvt_utf8_utf16
, और कुछ codecvt
विशेषज्ञताओं। साथ में ये मानक पहलू निम्नलिखित सभी रूपांतरण प्रदान करते हैं। (नोट: निम्नलिखित सूची में, बाईं ओर एन्कोडिंग हमेशा क्रमबद्ध स्ट्रिंग / स्ट्रीमब्यूफ़ है, और दाईं ओर एन्कोडिंग हमेशा डीज़रीलाइज़्ड स्ट्रिंग / स्ट्रीमब्यूफ़ है; मानक दोनों दिशाओं में रूपांतरण की अनुमति देता है)।
codecvt_utf8<char16_t>
, और codecvt_utf8<wchar_t>
कहाँ sizeof(wchar_t) == 2
;codecvt_utf8<char32_t>
, codecvt<char32_t, char, mbstate_t>
, और codecvt_utf8<wchar_t>
जहां sizeof(wchar_t) == 4
;codecvt_utf16<char16_t>
, और codecvt_utf16<wchar_t>
कहां sizeof(wchar_t) == 2
;codecvt_utf16<char32_t>
, और codecvt_utf16<wchar_t>
कहाँ sizeof(wchar_t) == 4
;codecvt_utf8_utf16<char16_t>
, codecvt<char16_t, char, mbstate_t>
, और codecvt_utf8_utf16<wchar_t>
जहां sizeof(wchar_t) == 2
;codecvt<wchar_t, char_t, mbstate_t>
codecvt<char, char, mbstate_t>
।इनमें से कई उपयोगी हैं, लेकिन यहां बहुत अजीब चीजें हैं।
सबसे पहले - पवित्र उच्च सरोगेट! नामकरण योजना गड़बड़ है।
फिर, UCS-2 का बहुत समर्थन है। यूसीएस -2 यूनिकोड 1.0 से एक एन्कोडिंग है जो 1996 में छोड़ी गई थी क्योंकि यह केवल मूल बहुभाषी विमान का समर्थन करता है। समिति ने 20 साल पहले एक एन्कोडिंग पर ध्यान केंद्रित करना क्यों उचित समझा, मुझे नहीं पता irable। यह अधिक एन्कोडिंग के लिए समर्थन की तरह नहीं है खराब या कुछ भी है, लेकिन यूसीएस -2 यहां अक्सर दिखाता है।
मैं कहूंगा कि char16_t
स्पष्ट रूप से UTF-16 कोड इकाइयों के भंडारण के लिए है। हालांकि, यह मानक का एक हिस्सा है जो अन्यथा सोचता है। codecvt_utf8<char16_t>
UTF-16 से कोई लेना-देना नहीं है। उदाहरण के लिए, wstring_convert<codecvt_utf8<char16_t>>().to_bytes(u"\U0001F34C")
ठीक संकलन करेगा, लेकिन बिना शर्त विफल हो जाएगा: इनपुट को यूसीएस -2 स्ट्रिंग के रूप में माना जाएगा u"\xD83C\xDF4C"
, जिसे यूटीएफ -8 में परिवर्तित नहीं किया जा सकता है, क्योंकि यूटीएफ -8 0xD800-0xFFFF में किसी भी मूल्य को एन्कोड नहीं कर सकता है।
अभी भी UCS-2 मोर्चे पर, इन पहलुओं के साथ UTF-16 स्ट्रिंग में UTF-16 बाइट स्ट्रीम से पढ़ने का कोई तरीका नहीं है। यदि आपके पास UTF-16 बाइट्स का एक अनुक्रम है, तो आप इसे स्ट्रिंग में स्ट्रिंग में शामिल नहीं कर सकते char16_t
। यह आश्चर्य की बात है, क्योंकि यह कम या ज्यादा एक पहचान रूपांतरण है। हालांकि इससे भी ज्यादा आश्चर्य की बात यह है कि यह तथ्य है कि यूटीएस -16 स्ट्रीम से यूसीएस -2 स्ट्रिंग के साथ डिसरसाइज करने का समर्थन है codecvt_utf16<char16_t>
, जो वास्तव में एक हानिकारक रूपांतरण है।
UTF-16-as-bytes समर्थन काफी अच्छा है, हालांकि: यह एक BOM से धीरज का पता लगाने, या कोड में स्पष्ट रूप से चयन करने का समर्थन करता है। यह BOM के साथ और उसके बिना भी उत्पादन का समर्थन करता है।
कुछ और दिलचस्प रूपांतरण संभावनाएं अनुपस्थित हैं। UTF-16 बाइट स्ट्रीम या स्ट्रिंग से एक UTF-8 स्ट्रिंग में deserialize करने का कोई तरीका नहीं है, क्योंकि UTF-8 को deserialized फॉर्म के रूप में कभी भी समर्थित नहीं किया गया है।
और यहाँ संकीर्ण / विस्तृत दुनिया UTF / UCS दुनिया से पूरी तरह से अलग है। पुरानी शैली की संकीर्ण / विस्तृत एन्कोडिंग और किसी भी यूनिकोड एन्कोडिंग के बीच कोई रूपांतरण नहीं हैं।
इनपुट / आउटपुट लाइब्रेरी
I / O लाइब्रेरी का उपयोग यूनिकोड एन्कोडिंग में पाठ को पढ़ने और लिखने के लिए किया जा सकता है wstring_convert
और wbuffer_convert
ऊपर वर्णित सुविधाओं का उपयोग कर । मुझे नहीं लगता कि मानक पुस्तकालय के इस हिस्से द्वारा समर्थित होने की आवश्यकता है।
नियमित अभिव्यक्ति पुस्तकालय
मैंने पहले भी स्टैक ओवरफ्लो पर C ++ रीगेक्स और यूनिकोड के साथ समस्याओं पर विस्तार किया है । मैं यहां उन सभी बिंदुओं को नहीं दोहराऊंगा, लेकिन केवल यह बताता हूं कि C ++ रीजैक्स में स्तर 1 यूनिकोड समर्थन नहीं है, जो कि हर जगह UTF-32 का उपयोग किए बिना उन्हें उपयोग करने योग्य बनाने के लिए न्यूनतम न्यूनतम है।
बस?
हाँ बस यही। वह मौजूदा कार्यक्षमता है। यूनिकोड कार्यक्षमता बहुत है जो सामान्यीकरण या पाठ विभाजन एल्गोरिदम की तरह कहीं नहीं देखी जा सकती है।
U + 1F4A9 । क्या C ++ में कुछ बेहतर यूनिकोड समर्थन प्राप्त करने का कोई तरीका है?
सामान्य संदिग्धों: ICU और Boost.Locale ।
Ly एक बाइट स्ट्रिंग, अनिश्चित रूप से, बाइट्स की एक स्ट्रिंग है, अर्थात, char
ऑब्जेक्ट। हालांकि, एक विस्तृत स्ट्रिंग शाब्दिक के विपरीत , जो हमेशा wchar_t
वस्तुओं का एक सरणी होता है, इस संदर्भ में एक "विस्तृत स्ट्रिंग" आवश्यक रूप से wchar_t
वस्तुओं का एक स्ट्रिंग नहीं है । वास्तव में, मानक कभी भी स्पष्ट रूप से परिभाषित नहीं करता है कि "वाइड स्ट्रिंग" का क्या अर्थ है, इसलिए हमें उपयोग से अर्थ का अनुमान लगाने के लिए छोड़ दिया गया है। चूंकि मानक शब्दावली सुस्त और भ्रमित है, इसलिए मैं स्पष्टता के नाम पर अपने स्वयं के उपयोग करता हूं।
UTF-16 जैसी एन्कोडिंग को अनुक्रम के रूप में संग्रहीत किया जा सकता है char16_t
, जिसमें तब कोई धीरज नहीं होता है; या उन्हें बाइट्स के अनुक्रम के रूप में संग्रहीत किया जा सकता है, जिसमें एंडियननेस होता है (बाइट्स की प्रत्येक लगातार जोड़ी char16_t
एंडियननेस के आधार पर एक अलग मूल्य का प्रतिनिधित्व कर सकती है )। मानक इन दोनों रूपों का समर्थन करता है। char16_t
कार्यक्रम में आंतरिक हेरफेर के लिए एक अनुक्रम अधिक उपयोगी है। बाइट्स का एक क्रम बाहरी दुनिया के साथ ऐसे तार का आदान-प्रदान करने का तरीका है। "बाइट" और "वाइड" के बजाय मैं जिन शब्दों का उपयोग करूँगा, वे इस प्रकार "क्रमबद्ध" और "डिसेरिएलाइज़्ड" हैं।
‡ यदि आप कहने वाले हैं "लेकिन विंडोज!" अपना 🐎🐎 पकड़ो । Windows 2000 से Windows के सभी संस्करण UTF-16 का उपयोग करते हैं।
☦ हां, मैं ग्रोस एस्ज़ेट (,) के बारे में जानता हूं , लेकिन भले ही आप रात भर में सभी जर्मन स्थानों को overnight अपरकेस में बदल दें, फिर भी बहुत सारे अन्य मामले हैं जहां यह विफल हो जाएगा। Uppercasing U + FB00 U sʟɪɢᴀᴛᴜʀᴇ ғғ ing की कोशिश करें। कोई ʟᴀᴛɪɴ ᴄᴀᴘɪᴛᴀʟ ʟɪɢᴀᴛᴜʀᴇ ғғ नहीं है; यह सिर्फ दो एफएस पर अपरकेस है। या U + 01F0 ʟᴀᴛɪɴ sᴍᴀʟʟ + 0 0 0; कोई पूर्वनिर्धारित पूंजी नहीं है; यह सिर्फ एक राजधानी जे और एक संयोजन कैरन के लिए अपरकेस है।
यूनिकोड मानक लाइब्रेरी ( समर्थित के किसी भी उचित अर्थ के लिए) द्वारा समर्थित नहीं है ।
std::string
इससे बेहतर नहीं है std::vector<char>
: यह यूनिकोड (या किसी अन्य प्रतिनिधित्व / एन्कोडिंग) के लिए पूरी तरह से अनजान है और बस इसकी सामग्री को बाइट्स के बूँद के रूप में मानते हैं ।
आप केवल दुकान और कड़ी लगाकर जोड़ना करने के लिए की जरूरत है धब्बे , यह बहुत अच्छी तरह से काम करता है; लेकिन जैसे ही आप यूनिकोड कार्यक्षमता ( कोड अंक , अंगूर की संख्या आदि) की इच्छा करते हैं , आप भाग्य से बाहर हो जाते हैं।
इसके लिए मुझे पता है कि एकमात्र व्यापक पुस्तकालय आईसीयू है । C ++ इंटरफ़ेस को जावा एक से लिया गया था, हालांकि यह मुहावरेदार होने से बहुत दूर है।
आप सुरक्षित रूप से एक में UTF-8 स्टोर कर सकते हैं std::string
(या में एक char[]
या char*
, उस बात के लिए), तथ्य यह है कि एक यूनिकोड NUL (U + 0000) UTF-8 में एक अशक्त बाइट है की वजह से है और इस एकमात्र तरीका एक अशक्त है कि यूटीएफ -8 में बाइट हो सकती है। इसलिए, आपके UTF-8 स्ट्रिंग्स को C और C ++ स्ट्रिंग फ़ंक्शन के सभी के अनुसार ठीक से समाप्त किया जाएगा, और आप उन्हें C ++ iostreams (सहित std::cout
और std::cerr
जब तक आपका लोकल UTF-8 है) के साथ चारों ओर स्लिंग कर सकते हैं ।
आप std::string
UTF-8 के लिए क्या नहीं कर सकते हैं कोड बिंदुओं में लंबाई है। std::string::size()
आपको बाइट्स में स्ट्रिंग की लंबाई बताएगा , जो केवल यूटीएफ -8 के एएससीआईआई सबसेट के भीतर कोड बिंदुओं की संख्या के बराबर है।
यदि आपको कोड पॉइंट स्तर पर UTF-8 स्ट्रिंग्स पर काम करने की आवश्यकता है (अर्थात सिर्फ स्टोर नहीं करें और उन्हें प्रिंट करें) या यदि आप UTF-16 के साथ काम कर रहे हैं, जिसमें कई आंतरिक नल बाइट्स होने की संभावना है, तो आपको गौर करने की आवश्यकता है विस्तृत चरित्र स्ट्रिंग प्रकार।
std::string
बस ठीक nulls के साथ iostreams में फेंका जा सकता है।
c_str()
क्योंकि size()
अभी भी काम करता है। केवल टूटे हुए एपीआई (यानी जो सी दुनिया के अधिकांश की तरह एम्बेडेड नल को संभाल नहीं सकते हैं) टूट जाते हैं।
c_str()
क्योंकि c_str()
माना जाता है कि डेटा को एक शून्य-टर्म सी स्ट्रिंग के रूप में लौटाया जाता है --- जो कि असंभव है, इस तथ्य के कारण कि सी स्ट्रिंग में एम्बेडेड नल नहीं हो सकते हैं।
c_str()
अब बस के रूप में एक ही लौटाता है data()
, यानी यह सब। आकार लेने वाले API इसका उपभोग कर सकते हैं। एपीआई, जो नहीं कर सकते।
c_str()
यह सुनिश्चित करता है कि परिणाम NUL char-like ऑब्जेक्ट के बाद है, और मुझे नहीं लगता data()
है। नहींं, data()
अब जैसा दिखता है वैसा ही है। (बेशक, यह एपीआई के लिए आवश्यक नहीं है जो एक टर्मिनेटर खोज से इसे संदर्भित करने के बजाय आकार का उपभोग करता है)
C ++ 11 में यूनिकोड के लिए कुछ नए शाब्दिक स्ट्रिंग प्रकार हैं ।
दुर्भाग्य से गैर-समान एन्कोडिंग (जैसे यूटीएफ -8) के लिए मानक पुस्तकालय में समर्थन अभी भी खराब है। उदाहरण के लिए UTF-8 स्ट्रिंग की लंबाई (कोड-पॉइंट में) प्राप्त करने का कोई अच्छा तरीका नहीं है।
std::string
सकता है, लेकिन उदाहरण के लिए विधि स्ट्रिंग में बाइट्स की संख्या लौटाती है और कोड-पॉइंट की संख्या नहीं। length
ñ
'LATIN SMALL LETTER N WITH TILDE' (U + 00F1) (जो एक कोड बिंदु है) या 'LATIN SMALL LETTER N' (के रूप में लिख सकता है ) U + 006E) के बाद 'COMBINING TILDE' (U + 0303) जो दो कोड पॉइंट हैं।
LATIN SMALL LETTER N'
== मानता है या नहीं (U+006E) followed by 'COMBINING TILDE' (U+0303)
।
हालाँकि, एक बहुत ही उपयोगी पुस्तकालय है जिसे छोटे-utf8 कहा जाता है , जो मूल रूप से / के लिए एक ड्रॉप-इन प्रतिस्थापन है । इसका उद्देश्य अभी भी लापता utf8-string कंटेनर वर्ग के अंतराल को भरना है।std::string
std::wstring
यह utf8 स्ट्रिंग्स के साथ 'निपटने' का सबसे आरामदायक तरीका हो सकता है (यानी, यूनिकोड के सामान्यीकरण और समान सामान के बिना)। आप आराम से कोडपॉइंट पर काम करते हैं , जबकि आपका स्ट्रिंग रन-लेंथ-इनकोडेड char
s में एन्कोडेड रहता है ।