2010-03-27 18 views
14

में स्ट्रिंग प्रदर्शित करना मैं विंडोज़ के लिए केवल एक सी ++ प्रोग्राम पर काम कर रहा हूं जहां हमें "हमेशा std :: wstring का उपयोग करें" कहा गया था, लेकिन ऐसा लगता है कि टीम के किसी भी व्यक्ति के पास वास्तव में उससे अधिक समझ नहीं है।सी ++ के std :: wstring, UTF-16, UTF-8 के बारे में उलझन में और विंडोज़ GUI

मैंने पहले से ही "std::wstring VS std::string शीर्षक वाले प्रश्न को पढ़ा है। यह बहुत उपयोगी था, लेकिन मुझे अभी भी समझ में नहीं आता कि मेरी सारी समस्या के बारे में सारी जानकारी कैसे लागू करें।

प्रोग्राम मैं विंडोज़ जीयूआई में डेटा प्रदर्शित करने पर काम कर रहा हूं। वह डेटा एक्सएमएल के रूप में जारी है। हम एक्सएमएलटी का उपयोग करते हुए उस एक्सएमएल को एचटीएमएल या एक्सएसएल में बदलते हैं: एफओओ रिपोर्टिंग उद्देश्यों के लिए।

मैंने जो पढ़ा है उसके आधार पर मेरी भावना यह है कि HTML को यूटीएफ -8 के रूप में एन्कोड किया जाना चाहिए। मुझे जीयूआई विकास के बारे में बहुत कम पता है, लेकिन मैंने जो कुछ पढ़ा है, वह इंगित करता है कि जीयूआई सामान यूटीएफ -16 एन्कोडेड तारों पर आधारित है।

मैं यह समझने की कोशिश कर रहा हूं कि यह मुझे कहां छोड़ देता है। मान लें कि हम तय करते हैं कि हमारे सभी निरंतर डेटा यूटीएफ -8 एन्कोडेड एक्सएमएल होना चाहिए। क्या इसका मतलब यह है कि यूआई घटक में लगातार डेटा प्रदर्शित करने के लिए, मुझे वास्तव में यूटीएफ -16 ट्रांसकोडिंग प्रक्रिया में कुछ प्रकार के स्पष्ट यूटीएफ -8 प्रदर्शन करना चाहिए?

मुझे संदेह है कि मेरी व्याख्या स्पष्टीकरण का उपयोग कर सकती है, इसलिए यदि आप कोई प्रश्न पूछें तो मैं यह उपलब्ध कराने की कोशिश करूंगा।

उत्तर

7

NT4 के बाद से विंडोज यूनिकोड एन्कोडेड तारों पर आधारित है, हां। शुरुआती संस्करण यूसीएस -2 पर आधारित थे, जो पूर्ववर्ती या यूटीएफ -16 है, और इस प्रकार यूटीएफ -16 के सभी पात्रों का समर्थन नहीं करता है। बाद के संस्करण यूटीएफ -16 पर आधारित हैं। हालांकि, सभी ओएस यूटीएफ -16/यूसीएस -2 पर आधारित नहीं हैं। * उदाहरण के लिए, निक्स सिस्टम, इसके बजाय यूटीएफ -8 पर आधारित हैं।

यूटीएफ -8 लगातार डेटा संग्रहित करने के लिए एक बहुत अच्छी पसंद है। यह सभी यूनिकोड वातावरण में एक सार्वभौमिक रूप से समर्थित एन्कोडिंग है, और यह डेटा आकार और हानि-कम डेटा संगतता के बीच एक अच्छा संतुलन है।

हां, आपको एक्सएमएल का विश्लेषण करना होगा, इससे आवश्यक जानकारी निकालना होगा, और इसे डीकोड करना होगा और यूआई का उपयोग कर सकते हैं।

+3

यह कहना वास्तव में सटीक नहीं है कि * निक्स यूटीएफ -8 पर आधारित है जिस तरह से विंडोज यूटीएफ -16 पर आधारित है। यह लोकेल-परिभाषित वर्ण एन्कोडिंग (विंडोज टर्मिनोलॉजी, एएनएसआई में) पर आधारित है। POSIX की आवश्यकता है कि कुछ वर्ण (एनयूएल समेत) को एक बाइट में प्रदर्शित किया जाए, इसलिए यूटीएफ -16 और यूटीएफ -32 की अनुमति नहीं है, लेकिन यूटीएफ -8 है। – dan04

3

जीयूआई संबंधित तारों के लिए विंडोज़ पर std :: wstring का उपयोग करने का एक फायदा यह है कि आंतरिक रूप से सभी विंडोज एपीआई यूटीएफ -16 पर उपयोग और संचालन करते हैं। यदि आपने कभी देखा है कि सभी Win32 API कॉल के 2 संस्करण हैं जो स्ट्रिंग तर्क लेते हैं। उदाहरण के लिए, "संदेशबॉक्स" और "संदेशबॉक्स"। दोनों परिभाषाओं में मौजूद हैं, और वास्तव में आप कॉल कर सकते हैं या तो आप चाहते हैं, लेकिन अगर यूनिकोड समर्थन के साथ शामिल है सक्षम है, तो निम्न होगा:

#define MessageBox MessageBoxW 

तो फिर तुम कोशिश करते हैं और बनाने के लिए TCHAR और अन्य माइक्रोसॉफ्ट चाल में मिल एपीएसआई और यूनिकोड संस्करण दोनों वाले एपीआई से निपटना आसान है। संक्षेप में, आप या तो कॉल कर सकते हैं, लेकिन हुड के तहत यूनिकोड आधारित विंडोज कर्नेल, इसलिए यदि आप विस्तृत चार संस्करण का उपयोग नहीं करते हैं तो आप Win32 API कॉल को स्वीकार करने वाली प्रत्येक स्ट्रिंग के लिए यूनिकोड में कनवर्ट करने की लागत का भुगतान करेंगे। दो बाइट्स प्रत्येक चरित्र और कोड तालिकाओं यूनिकोड प्रारूप करने के लिए ज्यादातर नक्शे के लिए उपयोग किया जाता है:

UTF-16 and Windows kernel use

4

std :: wstring तकनीकी रूप से यूसीएस -2 है। यह समझना महत्वपूर्ण है कि यूसीएस -2 यूटीएफ -16 जैसा नहीं है! यूटीएफ -16 दो-बाइट रेंज के बाहर वर्णों का प्रतिनिधित्व करने के लिए "सरोगेट जोड़े" की अनुमति देता है, लेकिन यूसीएस -2 प्रत्येक चरित्र, अवधि के लिए बिल्कुल दो बाइट्स का उपयोग करता है।

आपकी स्थिति के लिए सबसे अच्छा नियम डिस्क को पढ़ने और लिखने पर आपके ट्रांसकोडिंग करना है। एक बार यह स्मृति में हो जाने पर, इसे यूसीएस -2 प्रारूप में रखें। विंडोज एपीआई इसे पढ़ेंगे जैसे कि यह यूटीएफ -16 था (जो कहने के लिए है, जबकि std :: wstring सरोगेट जोड़े की अवधारणा को समझ में नहीं आता है, अगर आप मैन्युअल रूप से उन्हें बनाते हैं (जो आप नहीं करेंगे, अगर आपकी एकमात्र भाषा है अंग्रेजी), विंडोज़ उन्हें पढ़ेगा)।

जब भी आप आधुनिक दिन में धारावाहिक प्रारूपों (जैसे एक्सएमएल) में डेटा पढ़ रहे हैं या बाहर कर रहे हैं, तो आपको शायद ट्रांसकोडिंग करने की आवश्यकता होगी। यह जीवन का एक अप्रिय और बहुत दुर्भाग्यपूर्ण तथ्य है, लेकिन अपरिहार्य है क्योंकि यूनिकोड एक चर-चौड़ाई वाला वर्ण एन्कोडिंग है और सी ++ में अधिकांश वर्ण-आधारित संचालन सरणी के रूप में किए जाते हैं, जिसके लिए आपको लगातार अंतर की आवश्यकता होती है।

उच्च स्तर के ढांचे, जैसे .NET, अधिकांश विवरण अस्पष्ट, लेकिन दृश्यों के पीछे, वे एक ही फैशन में ट्रांसकोडिंग को संभालने में कामयाब रहे हैं: वेरिएबल-चौड़ाई डेटा को निश्चित-चौड़ाई तारों में बदलना, उन्हें जोड़ना, और फिर आउटपुट के लिए आवश्यक होने पर उन्हें वापस चर-चौड़ाई एन्कोडिंग में बदलना।

+2

क्या कहते हैं कि std :: wstring यूसीएस -2 है? std :: wstring स्ट्रिंग के लिए बेस के रूप में wchar_t के बजाय och char का उपयोग करें। और wchar_t कार्यान्वयन निर्भर है। लेकिन मुझे लगता है कि अधिकांश आधुनिक 32/64-बिट सिस्टम में यह char16_t जैसा ही होगा। ईथर यूसीएस -2 या यूटीएफ -16 फिट होने के बाद से वे 16 बिट चौड़े होंगे। – jpyllman

+2

अच्छा बिंदु। std :: wstring तकनीकी रूप से किसी भी प्रकार का चरित्र एन्कोडिंग नहीं है। यह सिर्फ दो-बाइट चौड़े पात्र हैं। लेकिन यूटीएफ -16 ** ** ** बिट्स चौड़ा नहीं है! यह एक चरित्र को स्टोर करने के लिए 16 बिट्स के ** ** ** का उपयोग करता है, लेकिन यदि चरित्र की आवश्यकता होती है तो 32 बिट तक का उपयोग कर सकते हैं! इससे अनुप्रयोगों के खिलाफ कई बफर-ओवर्रून हमले हुए हैं जो अक्षरों में यूटीएफ -16 एन्कोडेड तारों को मापते हैं और फिर गलती से आवंटित (अक्षर + 1) * 2 बाइट स्टोरेज आवंटित करते हैं और स्ट्रिंग को अंधाधुंध कॉपी करते हैं! –

+0

@ डैन स्टोरी: और अगर इससे सिंगल ग्रैफेम में निपटने के लिए पात्रों को जोड़ना पड़ता है तो इससे भी बदतर हो सकता है। –

1

भले ही आप कहते हैं कि आपके डेटा में केवल अंग्रेज़ी है, तो आप शायद गलत हैं। चूंकि हम अब वैश्विक दुनिया में हैं, नाम/पते/आदि में विदेशी पात्र हैं। ठीक है, मुझे नहीं पता कि आपके पास किस प्रकार का डेटा है, लेकिन आम तौर पर मैं कहूंगा कि उपयोगकर्ता को डेटा संग्रहित करने और डेटा को प्रदर्शित करने के लिए यूनिकोड का समर्थन करने के लिए अपना एप्लिकेशन बनाएं। यह यूटीएफ -8 के साथ एक्सएमएल का उपयोग करने का सुझाव देगा, जब आप जीयूआई करते हैं तो विंडोज कॉल के यूनिकोड संस्करणों को स्टोर करने के लिए। और चूंकि विंडोज जीयूआई यूटीएफ -16 का उपयोग करता है, जहां प्रत्येक टोकन 16-बिट है, तो मैं 16-बिट चौड़ी स्ट्रिंग में एप्लिकेशन में डेटा संग्रहीत करने का सुझाव दूंगा। और मुझे लगता है कि विंडोज़ के लिए आपके कंपाइलर के पास इस उद्देश्य के लिए 16-बिट के रूप में std :: wstring होगा।

तो आपको यूटीएफ -16 और यूटीएफ -8 के बीच बहुत सारे रूपांतरण करना है। कुछ मौजूदा लाइब्रेरी के साथ ऐसा करें, उदाहरण के लिए ICU

+0

अभिशाप में यूटीएफ -16 के साथ एक्सएमएल में डेटा संग्रहित करने में कुछ भी गलत नहीं है। लेकिन मैं अलग-अलग प्रणालियों के बीच अधिक आसान पोर्टेबिलिटी के लिए यूटीएफ -8 का सुझाव दूंगा। – jpyllman

+2

यूटीएफ -8 लगभग हमेशा एक्सएमएल के लिए बेहतर विकल्प है, क्योंकि कंप्यूटिंग भाषा के रूप में अंग्रेजी का प्रावधान का अर्थ है कि अधिकांश एक्सएमएल दस्तावेजों में से अधिकांश मार्कअप वर्ण यूटीएफ -8 एन्कोडिंग की 8-बिट रेंज के अंदर गिरने जा रहे हैं , जिसके परिणामस्वरूप महत्वपूर्ण अंतरिक्ष बचत हुई। यह आम तौर पर तब भी लागू होता है जब दस्तावेज़ * सामग्री * की भाषा एक गैर-अंग्रेजी भाषा में है जो एक विस्तारित चरित्र सेट का उपयोग करती है। –

+2

और वास्तव में प्रोग्राम में std :: स्ट्रिंग का उपयोग करना और उनमें यूटीएफ -8 स्टोर करना बेहतर हो सकता है। और फिर जब आप कुछ प्रदर्शित करना चाहते हैं तो केवल विंडोज के लिए यूटीएफ -16 में कनवर्ट करें। केवल अन्य सभी अर्थों में यूटीएफ -8 के साथ काम करना। – jpyllman

5

AFAIK जब आप सी ++ में विंडोज़ पर std :: wstring के साथ काम करते हैं और फ़ाइलों में यूटीएफ -8 का उपयोग करके स्टोर करते हैं (जो अच्छा और उचित लगता है), तो फ़ाइल को लिखते समय आपको डेटा को यूटीएफ -8 में परिवर्तित करना होगा, और फ़ाइल से पढ़ने पर यूटीएफ -16 में वापस कनवर्ट करें। इस लिंक को देखें: Writing UTF-8 Files in C++

मैं प्रोजेक्ट के विजुअल स्टूडियो डिफ़ॉल्ट -> गुण -> कॉन्फ़िगरेशन गुण -> सामान्य -> ​​कैरेक्टर सेट -> यूनिकोड कैरेक्टर सेट का उपयोग करें, wchar_t प्रकार (यानी std :: wstring के साथ) और का उपयोग करें टीसीएचएआर प्रकार का उपयोग करें। (उदा। मैं सिर्फ strlen के wcslen संस्करण और _tcslen का उपयोग नहीं करता।)

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