2010-06-09 16 views
24

एक बहुत ही सरल प्रोग्राम मानते हैं कि:सी ++ में यूनिकोड का उपयोग कैसे करें?

  • एक नाम पूछें।
  • नाम को एक चर में संग्रहीत करें।
  • स्क्रीन पर परिवर्तनीय सामग्री प्रदर्शित करें।

यह इतना आसान है कि पहली बात यह है कि कोई सीखता है।

लेकिन मेरी समस्या यह है कि मुझे नहीं पता कि अगर मैं जापानी अक्षरों का उपयोग कर नाम दर्ज करता हूं तो मुझे यह कैसे करना है।

तो, अगर आप कैसे सी ++ में यह करने के लिए पता है, कृपया मुझे एक उदाहरण (है कि मैं संकलन कर सकते हैं और परीक्षण)

धन्यवाद दिखा।


उपयोगकर्ता362981: आपकी मदद के लिए धन्यवाद। मैंने कोड को संकलित किया जिसे आपने बिना किसी समस्या के लिखा था, उन्हें कंसोल विंडो दिखाई देती है और मैं इस पर किसी भी जापानी अक्षर (आईएमई का उपयोग करके) दर्ज नहीं कर सकता। इसके अलावा यदि मैं आपके कोड ("हैलो") में एक शब्द बदलता हूं जिसमें जापानी वर्ण हैं, तो यह इन्हें प्रदर्शित नहीं करेगा।

स्विसस्टैक: आपकी मदद के लिए भी धन्यवाद।

warning: deprecated conversion from string constant to 'wchar_t*' 
error: too few arguments to function 'int swprintf(wchar_t*, const wchar_t*, ...)' 
error: at this point in file 
warning: deprecated conversion from string constant to 'wchar_t*' 
+1

आपने प्लेटफ़ॉर्म का उल्लेख नहीं किया है, लेकिन विंडोज़ सीएमडी लाइन यूनिकोड को बहुत अच्छी तरह से संभाल नहीं सकती है। इस धागे को जांचें: http://stackoverflow.com/questions/379240/is-there-a-windows-command-shell-that-will-display-unicode-characters – zdav

उत्तर

1

wcout साथ अदालत की जगह, wcin साथ CIN प्रयास करें, और wstring के साथ स्ट्रिंग: लेकिन जब मैं अपने कोड संकलन मैं निम्नलिखित त्रुटि मिलती है। अपने मंच के आधार पर यह काम कर सकते हैं:

#include <iostream> 
#include <string> 

int main() { 
    std::wstring name; 
    std::wcout << L"Enter your name: "; 
    std::wcin >> name; 
    std::wcout << L"Hello, " << name << std::endl; 
} 

वहाँ अन्य तरीके हैं, लेकिन यह "कम से कम परिवर्तन" जवाब की तरह है।

+0

वास्तव में मुझे लगता है कि आपको अभी भी एक लोकेल बनाना है कंसोल का उपयोग एन्कोडिंग से मेल खाता है, और फिर 'std :: wcout.imbue' और' std :: wcin.imbue' (और माइक्रोस्कोफ्ट्स बग्गी एसएलएल कार्यान्वयन के साथ afaik एक 'std :: locale :: global wstreams का उपयोग करने से पहले 'aswell)। – smerlin

1
#include <stdio.h> 
#include <wchar.h> 

int main() 
{ 
    wchar_t name[256]; 

    wprintf(L"Type a name: "); 
    wscanf(L"%s", name); 

    wprintf(L"Typed name is: %s\n", name); 

    return 0; 
} 
+0

आप wscanf और wprintf चाहते हैं, स्ट्रिंग-रीडिंग और स्ट्रिंग-लेखन समकक्ष नहीं। –

+0

@ ओवेन: हाँ, मैंने इसे याद किया, धन्यवाद – Svisstack

1

आप अपनी पसंद के ओएस में सामान्य विस्तृत चरित्र समर्थन के साथ सरल कर सकते हैं, लेकिन आम तौर पर सी ++ नहीं है अच्छा निर्मित यूनिकोड के लिए समर्थन है, तो आप लंबे समय में बेहतर हो जाएगा ICU जैसे कुछ की तलाश में है।

36

आपको विस्तृत पात्रों के बारे में बहुत सारे जवाब मिलेंगे। विस्तृत वर्ण, विशेष रूप से wchar_tयूनिकोड के बराबर नहीं है। यूनिकोड स्टोर करने के लिए आप उन्हें (कुछ नुकसान के साथ) उपयोग कर सकते हैं, जैसे आप unsigned char कर सकते हैं। wchar_t बेहद सिस्टम-निर्भर है। Unicode Standard, version 5.2, chapter 5:

With the wchar_t wide character type, ANSI/ISO C provides for inclusion of fixed-width, wide characters. ANSI/ISO C leaves the semantics of the wide character set to the specific implementation but requires that the characters from the portable C execution set correspond to their wide character equivalents by zero extension.

और उस

The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compiler should not use wchar_t for storing Unicode text. The wchar_t type is intended for storing compiler-defined wide characters, which may be Unicode characters in some compilers.

के शब्दों में इसलिए, यह कार्यान्वयन परिभाषित है। यहां दो कार्यान्वयन हैं: लिनक्स पर, wchar_t 4 बाइट चौड़ा है, और यूटीएफ -32 एन्कोडिंग में टेक्स्ट का प्रतिनिधित्व करता है (वर्तमान लोकेल के बावजूद)। (या तो अपने सिस्टम के आधार पर बीई या ली, जो भी मूल है।) विंडोज़, हालांकि, 2 बाइट चौड़ा wchar_t है, और उनके साथ यूटीएफ -16 कोड इकाइयों का प्रतिनिधित्व करता है। पूरी तरह से अलग।

एक बेहतर मार्ग: स्थानीय लोगों के बारे में जानें, क्योंकि आपको यह जानना होगा।उदाहरण के लिए, क्योंकि मैं अपने वातावरण सेटअप उपयोग करने के लिए UTF-8 (यूनिकोड) है, निम्नलिखित कार्यक्रम यूनिकोड का उपयोग करेगा:

#include <iostream> 

int main() 
{ 
    setlocale(LC_ALL, ""); 
    std::cout << "What's your name? "; 
    std::string name; 
    std::getline(std::cin, name); 
    std::cout << "Hello there, " << name << "." << std::endl; 
    return 0; 
} 

...

$ ./uni_test 
What's your name? 佐藤 幹夫 
Hello there, 佐藤 幹夫. 
$ echo $LANG 
en_US.UTF-8 

लेकिन कुछ भी नहीं इसके बारे में यूनिकोड वहाँ । यह केवल वर्णों में पढ़ता है, जो यूटीएफ -8 के रूप में आते हैं क्योंकि मेरे पास पर्यावरण का तरीका है। मैं बस इतना कह सकता हूं कि "बिल्ली, मैं भाग का हिस्सा हूं, आइए आईएसओ -885 9-2 का उपयोग करें": अचानक, कार्यक्रम आईएसओ -885 9 -2 में इनपुट प्राप्त कर रहा है, लेकिन चूंकि यह सिर्फ इसे पुनर्जन्म दे रहा है, इससे कोई फर्क नहीं पड़ता , कार्यक्रम अभी भी सही ढंग से प्रदर्शन करेगा।

अब, अगर वह उदाहरण मेरे नाम पर पढ़ा गया था, और फिर इसे एक एक्सएमएल फ़ाइल में लिखने की कोशिश की, और बेवकूफ तरीके से <?xml version="1.0" encoding="UTF-8" ?> लिखा, तो यह सही होगा जब मेरा टर्मिनल यूटीएफ -8 में था, लेकिन गलत जब मेरा टर्मिनल आईएसओ -885 9 -2 में था। बाद के मामले में, इसे XML फ़ाइल में क्रमबद्ध करने से पहले इसे परिवर्तित करना होगा। (या, केवल XML फ़ाइल के लिए एन्कोडिंग के रूप में आईएसओ -885 9-2 लिखें।)

कई पॉज़िक्स सिस्टम पर, वर्तमान लोकेल आमतौर पर यूटीएफ -8 है, क्योंकि यह उपयोगकर्ता को कई फायदे प्रदान करता है, लेकिन यह ' टी गारंटी है। यूटीएफ -8 से stdout को आउटपुट करना आमतौर पर सही होगा, लेकिन हमेशा नहीं। मान लें कि मैं आईएसओ -885 9 -2 का उपयोग कर रहा हूं: यदि आप मेरे टर्मिनल पर एक आईएसओ -885 9 -1 "è" (0xE8) को बिना किसी आउटपुट आउटपुट करते हैं, तो मुझे एक "č" (0xE8) दिखाई देगा। इसी तरह, यदि आप एक यूटीएफ -8 "è" (0xC3 0xA8) आउटपुट करते हैं, तो मैं देखूंगा (आईएसओ -885 9 -2) "è" (0xC3 0xA8)। गलत वर्णों के इस बारफिंग को Mojibake कहा गया है।

अक्सर, आप बस डेटा को चारों ओर घुमा रहे हैं, और इससे कोई फर्क नहीं पड़ता। जब आप डेटा को क्रमबद्ध करने की आवश्यकता होती है तो यह आम तौर पर खेल में आता है। (कई इंटरनेट प्रोटोकॉल यूटीएफ -8 या यूटीएफ -16 का उपयोग करते हैं, उदाहरण के लिए: यदि आपको आईएसओ -885 9 -2 टर्मिनल से डेटा मिला है, या Windows-1252 में एन्कोड की गई एक टेक्स्ट फ़ाइल है, तो आपको इसे परिवर्तित करना होगा, या आप Mojibake भेजना।)

अफसोस की बात है, यह सी और सी ++ दोनों में यूनिकोड समर्थन की स्थिति के बारे में है। आपको याद रखना होगा: ये भाषाएं वास्तव में सिस्टम-अज्ञेयवादी हैं, और इसे करने के किसी भी विशेष तरीके से बंधे नहीं हैं। इसमें चरित्र-सेट शामिल हैं। यूनिकोड और अन्य चरित्र सेटों से निपटने के लिए, वहां कई पुस्तकालय हैं।

अंत में, यह वास्तव में जटिल नहीं है: जानें कि आपके डेटा में एन्कोडिंग क्या है, और जानें कि आपका आउटपुट क्या एन्कोडिंग होना चाहिए। यदि वे समान नहीं हैं, तो आपको एक रूपांतरण करने की आवश्यकता है। यह लागू होता है कि आप std::cout या std::wcout का उपयोग कर रहे हैं या नहीं। मेरे उदाहरणों में, stdin या std::cin और stdout/std::cout कभी-कभी यूटीएफ -8 में कभी-कभी आईएसओ -885 9-2 में थे।

+1

एक यूटीएफ -8 "è" '0xC3 0xA8' है,' 0xE8' नहीं। आप शायद आईएसओ -885 9 -1 मतलब था। – dan04

+0

@ dan04: उत्कृष्ट पकड़, धन्यवाद! '0xE8' यूनिकोड कोड बिंदु है (लेकिन, जैसा आपने कहा था, यूटीएफ -8 एन्कोडिंग नहीं)" è "के लिए। मैंने अपना उदाहरण अपडेट कर लिया है। – Thanatos

0

पूर्व अपेक्षित: http://www.joelonsoftware.com/articles/Unicode.html

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

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

सिद्धांत यह है कि एक यूनिकोड चरित्र 2 बाइट या अधिक ले सकता है, लेकिन यह अभी भी सच है और इससे कुछ भ्रम पैदा हो सकता है। क्या हमें 3 या 4 बाइट्स में कोड पॉइंट्स स्टोर नहीं करना चाहिए, जो वास्तव में सभी यूनिकोड वर्णों का प्रतिनिधित्व करता है? विज़ुअल सी ++ wchar_t में यूनिकोड संग्रहीत क्यों करता है, जो केवल 2 बाइट्स है, स्पष्ट रूप से प्रत्येक यूनिकोड कोड बिंदु को स्टोर करने के लिए पर्याप्त नहीं है?

विज़ुअल सी ++ में 2 बाइट्स में यूनिकोड वर्ण कोड बिंदु को संग्रहीत करने का कारण वास्तव में एक ही कारण है कि हम ASCII (= अंग्रेज़ी) वर्ण को एक बाइट में क्यों संग्रहीत कर रहे थे। उस समय, हम केवल अंग्रेजी के बारे में सोच रहे थे, इसलिए एक बाइट पर्याप्त था। अब हम वहां से अधिकतर अंतरराष्ट्रीय भाषाओं के बारे में सोच रहे हैं, लेकिन हम सभी 2 बाइट्स का उपयोग नहीं कर रहे हैं जो पर्याप्त है। हां यह सच है कि यह प्रतिनिधित्व हमें उन कोड बिंदुओं का प्रतिनिधित्व करने की अनुमति नहीं देगा जो 3 बाइट्स या अधिक लेते हैं, लेकिन हमें अभी तक उन परवाह नहीं है क्योंकि उन लोगों ने अभी तक कंप्यूटर खरीदा नहीं है। हां हम 3 या 4 बाइट्स का उपयोग नहीं कर रहे हैं क्योंकि हम अभी भी स्मृति के साथ चिपके हुए हैं, क्यों हर चरित्र के साथ अतिरिक्त 0 (शून्य) बाइट स्टोर करते हैं जब हम इसे कभी भी (उस भाषा) का उपयोग नहीं करेंगे। फिर यह वही कारण है जो एएससीआईआई एक बाइट में प्रत्येक चरित्र को स्टोर कर रहा था, क्यों एक चरित्र को 2 या अधिक बाइट्स में स्टोर करें, जब एक बाइट में अंग्रेजी का प्रतिनिधित्व किया जा सकता है और उन अतिरिक्त विशेष पात्रों के लिए अतिरिक्त जगह!

सिद्धांत में 2 बाइट प्रत्येक यूनिकोड कोड बिंदु प्रस्तुत करने के लिए पर्याप्त नहीं हैं, लेकिन यह कुछ भी पकड़ने के लिए पर्याप्त है जिसे हम अब तक परवाह कर सकते हैं। एक वास्तविक यूनिकोड स्ट्रिंग प्रस्तुति प्रत्येक चरित्र को 4 बाइट्स में स्टोर कर सकती है लेकिन हमें केवल उन भाषाओं की परवाह नहीं है।

अब से 1000 साल की कल्पना करें जब हम दोस्ताना एलियंस और बहुतायत में पाते हैं और उनके अनगिनत भाषाओं को शामिल करने के साथ संवाद करना चाहते हैं। उनके सभी कोड बिंदुओं को समायोजित करने के लिए एक यूनिकोड चरित्र का आकार शायद 8 बाइट तक बढ़ेगा। इसका मतलब यह नहीं है कि हमें अब प्रत्येक यूनिकोड चरित्र के लिए 8 बाइट्स का उपयोग शुरू करना चाहिए। मेमोरी सीमित संसाधन है, हम जो भी चाहते हैं उसे आवंटित करते हैं।

क्या मैं यूनिकोड स्ट्रिंग को सी स्टाइल स्ट्रिंग के रूप में संभाल सकता हूं?

सी ++ में एक एएससीआईआई तारों को अभी भी सी ++ में संभाला जा सकता है और यह अपने चार * पॉइंटर द्वारा इसे पकड़कर काफी आम है जहां सी कार्यों को लागू किया जा सकता है। हालांकि यूनिकोड स्ट्रिंग पर वर्तमान सी स्टाइल स्ट्रिंग फ़ंक्शंस को लागू करने से कोई अर्थ नहीं आएगा क्योंकि इसमें एक एकल नल बाइट हो सकता है जो सी स्ट्रिंग को समाप्त करता है।

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

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

मैं यूनिकोड स्ट्रिंग को कैसे इंडेक्स कर सकता हूं?

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

नल बाइट को समाप्त करने वाली स्ट्रिंग का क्या होता है?

यूनिकोड स्ट्रिंग अभी भी न्यूल बाइट द्वारा समाप्त कर रहे हैं? क्या एक एकल नल बाइट स्ट्रिंग को समाप्त करने के लिए पर्याप्त है? यह एक कार्यान्वयन प्रश्न है लेकिन एक पूर्ण बाइट अभी भी एक यूनिकोड कोड बिंदु है और हर दूसरे कोड बिंदु की तरह, यह अभी भी किसी अन्य के रूप में समान होना चाहिए (विशेष रूप से जब कोई एन्कोडिंग नहीं)। तो यूनिकोड स्ट्रिंग कार्यान्वयन wchar_t पर आधारित है, तो नल वर्ण दो बाइट्स भी होना चाहिए। सभी यूनिकोड कोड बिंदुओं को उसी आकार से प्रदर्शित किया जाएगा चाहे वह एक शून्य बाइट या कोई अन्य हो।

क्या विज़ुअल सी ++ डीबगर यूनिकोड टेक्स्ट दिखाता है?

हां, यदि टेक्स्ट बफर टाइप किया गया है तो एलपीडब्लूस्ट्र या कोई अन्य प्रकार जो यूनिकोड, विजुअल स्टूडियो 2005 का समर्थन करता है और डीबगर घड़ी विंडो में अंतर्राष्ट्रीय पाठ प्रदर्शित करने का समर्थन करता है (प्रदान किए गए फोंट और भाषा पैक निश्चित रूप से स्थापित होते हैं)।

सारांश:

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

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

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