यूनिकोड पाठ को संसाधित करने के लिए दो चरण हैं। पहला है "मैं इसे कैसे इनपुट कर सकता हूं और बिना जानकारी खोए इसे आउटपुट कर सकता हूं"। दूसरा है "मैं स्थानीय भाषा सम्मेलनों के अनुसार पाठ का इलाज कैसे करूं"।
tchrist की पोस्ट दोनों को कवर करती है, लेकिन दूसरा हिस्सा वह है जहाँ उसके पोस्ट का 99% टेक्स्ट आता है। अधिकांश प्रोग्राम I / O को सही तरीके से हैंडल नहीं करते हैं, इसलिए यह समझना महत्वपूर्ण है कि इससे पहले कि आप भी सामान्यीकरण और टकराव के बारे में चिंता करना शुरू कर दें।
इस पोस्ट का उद्देश्य उस पहली समस्या को हल करना है
जब आप पर्ल में डेटा पढ़ते हैं, तो यह परवाह नहीं करता है कि यह एन्कोडिंग क्या है। यह कुछ मेमोरी को आवंटित करता है और बाइट्स को वहां से हटा देता है। यदि आप कहते हैं print $str
, तो यह आपके टर्मिनल के लिए उन बाइट्स को उड़ा देता है, जो शायद यह सब कुछ मानने के लिए सेट है जो इसे लिखा गया है UTF-8, और आपका पाठ दिखाता है।
अद्भुत।
को छोड़कर, यह नहीं है। यदि आप डेटा को पाठ के रूप में मानने का प्रयास करते हैं, तो आप देखेंगे कि कुछ बुरा हो रहा है। आपको यह देखने की ज़रूरत नहीं length
है कि पर्ल आपके स्ट्रिंग के बारे में क्या सोचता है और आप अपनी स्ट्रिंग के बारे में क्या सोचते हैं। एक-लाइनर लिखें: perl -E 'while(<>){ chomp; say length }'
और टाइप करें 文字化け
और आपको 12 ... सही उत्तर नहीं, 4।
ऐसा इसलिए है क्योंकि पर्ल मानता है कि आपका स्ट्रिंग टेक्स्ट नहीं है। आपको यह बताना होगा कि यह पाठ है इससे पहले कि यह आपको सही उत्तर देगा।
यह काफी आसान है; एनकोड मॉड्यूल में ऐसा करने के लिए कार्य हैं। सामान्य प्रविष्टि बिंदु Encode::decode
(या use Encode qw(decode)
, निश्चित रूप से) है। यह फ़ंक्शन बाहरी दुनिया से कुछ स्ट्रिंग लेता है (जिसे हम "ऑक्टेट्स" कहेंगे, "8-बिट बाइट्स" कहने का तरीका), और इसे कुछ पाठ में बदल देता है जिसे पर्ल समझ जाएगा। पहला तर्क एक वर्ण एन्कोडिंग नाम है, जैसे "UTF-8" या "ASCII" या "EUC-JP"। दूसरा तर्क स्ट्रिंग है। वापसी मान पाठ युक्त पर्ल स्केलर है।
(वहाँ भी है Encode::decode_utf8
, जो एन्कोडिंग के लिए UTF-8 मानता है।)
यदि हम अपने वन-लाइनर को फिर से लिखते हैं:
perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'
हम "化 化 में टाइप करते हैं और परिणाम के रूप में" 4 "प्राप्त करते हैं। सफलता।
वहीं, पर्ल में 99% यूनिकोड समस्याओं का समाधान है।
कुंजी यह है कि जब भी कोई पाठ आपके कार्यक्रम में आता है, तो आपको उसे डिकोड करना होगा। इंटरनेट पात्रों को प्रसारित नहीं कर सकता। फ़ाइलें वर्णों को संग्रहीत नहीं कर सकती हैं। आपके डेटाबेस में कोई वर्ण नहीं हैं। केवल ऑक्टेट हैं, और आप ऑक्ट्स को पर्ल के पात्रों के रूप में नहीं मान सकते। आपको एनकोड मॉड्यूल के साथ पर्ल वर्णों में एन्कोडेड ओकटेट को डीकोड करना होगा।
समस्या का दूसरा हिस्सा आपके प्रोग्राम से डेटा प्राप्त कर रहा है। यह आसान है; आप बस कहते हैं use Encode qw(encode)
, यह तय करें कि आपका डेटा किस एन्कोडिंग में होगा (UTF-8 टर्मिनलों के लिए जो UTF-8, UTF-16 को विंडोज़ पर फ़ाइलों के लिए समझा जाता है, आदि), और फिर आउटपुट के encode($encoding, $data)
बजाय आउटपुट का परिणाम $data
।
यह ऑपरेशन पर्ल के वर्णों को परिवर्तित करता है, जो कि आपके प्रोग्राम को संचालित करता है, बाहरी दुनिया द्वारा उपयोग किए जा सकने वाले ऑक्टेट पर। यह बहुत आसान होगा यदि हम केवल इंटरनेट पर या अपने टर्मिनलों पर वर्ण भेज सकते हैं, लेकिन हम नहीं कर सकते: केवल ओकटेट। इसलिए हमें पात्रों को अष्टक में बदलना होगा, अन्यथा परिणाम अपरिभाषित हैं।
संक्षेप में: सभी आउटपुट को एनकोड करें और सभी इनपुट को डीकोड करें।
अब हम तीन मुद्दों के बारे में बात करेंगे जो इसे थोड़ा चुनौतीपूर्ण बनाते हैं। पहला पुस्तकालय है। क्या वे पाठ को सही ढंग से संभालते हैं? जवाब है ... वे कोशिश करते हैं। यदि आप एक वेब पेज डाउनलोड करते हैं, तो LWP आपको अपना परिणाम वापस पाठ के रूप में देगा। यदि आप परिणाम पर सही विधि कहते हैं, तो यह (और ऐसा ही होता है decoded_content
, नहीं content
, जो कि सर्वर से प्राप्त केवल ओकटेट स्ट्रीम है।) डेटाबेस ड्राइवर परतदार हो सकते हैं; यदि आप DBD का उपयोग करते हैं :: SQLite बस पर्ल के साथ, यह काम करेगा, लेकिन अगर किसी अन्य टूल ने आपके डेटाबेस में UTF-8 के अलावा कुछ एन्कोडिंग के रूप में संग्रहीत पाठ को रखा है ... अच्छी तरह से ... यह सही ढंग से संभाला नहीं जा रहा है। जब तक आप इसे सही तरीके से संभालने के लिए कोड नहीं लिखते हैं।
आउटपुट डेटा आमतौर पर आसान होता है, लेकिन यदि आप "प्रिंट में विस्तृत चरित्र" देखते हैं, तो आप जानते हैं कि आप कहीं एन्कोडिंग को गड़बड़ कर रहे हैं। उस चेतावनी का अर्थ है "हे, आप बाहरी दुनिया में पर्ल पात्रों को लीक करने की कोशिश कर रहे हैं और इसका कोई मतलब नहीं है"। आपका कार्यक्रम काम करता प्रतीत होता है (क्योंकि दूसरा छोर आमतौर पर कच्चे पर्ल पात्रों को सही ढंग से संभालता है), लेकिन यह बहुत टूट गया है और किसी भी समय काम करना बंद कर सकता है। एक स्पष्ट के साथ इसे ठीक करें Encode::encode
!
दूसरी समस्या UTF-8 एनकोडेड सोर्स कोड है। जब तक आप use utf8
प्रत्येक फ़ाइल के शीर्ष पर नहीं कहते हैं , तब तक पर्ल यह नहीं मानेगा कि आपका स्रोत कोड UTF-8 है। इसका मतलब है कि हर बार जब आप कुछ कहते हैं my $var = 'ほげ'
, तो आप अपने प्रोग्राम में कचरा इंजेक्ट कर रहे हैं जो पूरी तरह से सब कुछ तोड़ देगा। आपको "utf8" का उपयोग करने की आवश्यकता नहीं है, लेकिन यदि आप नहीं करते हैं, तो आपको अपने प्रोग्राम में किसी भी गैर- ASCII वर्ण का उपयोग नहीं करना चाहिए ।
तीसरी समस्या यह है कि पर्ल द पास्ट को कैसे हैंडल करता है। बहुत समय पहले, यूनिकोड जैसी कोई चीज नहीं थी, और पर्ल ने माना कि सब कुछ लैटिन -1 पाठ या द्विआधारी था। इसलिए जब डेटा आपके कार्यक्रम में आता है और आप इसे पाठ के रूप में मानने लगते हैं, तो पर्ल प्रत्येक ऑक्टेट को लैटिन -1 वर्ण के रूप में मानता है। इसीलिए, जब हमने "化 け," की लंबाई पूछी, तो हमें मिला 12. पर्ल ने अनुमान लगाया था कि हम लैटिन -1 स्ट्रिंग "åååã" पर काम कर रहे थे (जो कि 12 अक्षर हैं, जिनमें से कुछ नॉन-प्रिंटिंग हैं)।
इसे एक "निहित उन्नयन" कहा जाता है, और यह पूरी तरह से उचित काम है, लेकिन यह नहीं है कि आप क्या चाहते हैं यदि आपका पाठ लैटिन -1 नहीं है। इसलिए इनपुट को स्पष्ट रूप से डिकोड करना महत्वपूर्ण है: यदि आप ऐसा नहीं करते हैं, तो पर्ल होगा, और यह गलत हो सकता है।
लोग मुश्किल में पड़ जाते हैं, जहां उनका आधा डेटा एक उचित चरित्र स्ट्रिंग है, और कुछ अभी भी द्विआधारी है। पर्ल उस हिस्से की व्याख्या करेगा जो अभी भी द्विआधारी है क्योंकि यह लैटिन -1 पाठ है और फिर इसे सही चरित्र डेटा के साथ संयोजित करें। यह आपके पात्रों को सही ढंग से आपके प्रोग्राम को तोड़ने का काम कर देगा, लेकिन वास्तव में, आपने इसे पर्याप्त रूप से तय नहीं किया है।
यहां एक उदाहरण दिया गया है: आपके पास एक प्रोग्राम है जो एक UTF-8-एन्कोडेड पाठ फ़ाइल को पढ़ता है, आप PILE OF POO
प्रत्येक लाइन के लिए एक यूनिकोड से निपटते हैं , और आप इसे प्रिंट करते हैं। आप इसे लिखें:
while(<>){
chomp;
say "$_ 💩";
}
और फिर कुछ UTF-8 एन्कोडेड डेटा पर चलते हैं, जैसे:
perl poo.pl input-data.txt
यह प्रत्येक पंक्ति के अंत में एक पू के साथ UTF-8 डेटा प्रिंट करता है। बिल्कुल सही, मेरा कार्यक्रम काम करता है!
लेकिन नहीं, तुम सिर्फ द्विआधारी संघनन कर रहे हो। आप फ़ाइल से ऑक्टेट पढ़ रहे हैं, \n
चॉम्प के साथ निकाल रहे हैं , और फिर PILE OF POO
चरित्र के UTF-8 में बाइट्स से निपट रहे हैं । जब आप फ़ाइल से डेटा को डीकोड करने और आउटपुट को एनकोड करने के लिए अपने प्रोग्राम को संशोधित करते हैं, तो आप देखेंगे कि आपको पू के बजाय कचरा ("of ©") मिलेगा। यह आपको विश्वास दिलाएगा कि इनपुट फ़ाइल को डिकोड करना गलत काम है। यह।
समस्या यह है कि पू को अव्यवस्थित रूप से लैटिन -1 के रूप में उन्नत किया जा रहा है। यदि आप use utf8
बाइनरी के बजाय शाब्दिक पाठ बनाते हैं, तो यह फिर से काम करेगा!
(यह एक नंबर की समस्या है जो मुझे यूनिकोड के साथ लोगों की मदद करते समय दिखाई देती है। उन्होंने सही भाग किया और इससे उनका कार्यक्रम टूट गया। यह अपरिभाषित परिणामों से दुखी है: आपके पास लंबे समय तक काम करने का कार्यक्रम हो सकता है, लेकिन जब आप इसे सुधारना शुरू करते हैं। यह टूट जाता है। चिंता मत करो, यदि आप अपने प्रोग्राम में एनकोड / डीकोड स्टेटमेंट जोड़ रहे हैं और यह टूट जाता है, तो इसका मतलब है कि आपके पास काम करने के लिए काम है। अगली बार, जब आप शुरुआत से यूनिकोड को ध्यान में रखते हैं, तो यह होगा। बहुत आसान!)
वास्तव में आपको पर्ल और यूनिकोड के बारे में जानना चाहिए। यदि आप पर्ल को बताते हैं कि आपका डेटा क्या है, तो इसमें सभी लोकप्रिय प्रोग्रामिंग भाषाओं में सर्वश्रेष्ठ यूनिकोड का समर्थन है। यदि आप मानते हैं कि यह जादुई रूप से आपको पता होगा कि आप इसे किस प्रकार का पाठ खिला रहे हैं, तो आप अपने डेटा को अपरिवर्तनीय रूप से रद्दी करने जा रहे हैं। सिर्फ इसलिए कि आपका प्रोग्राम आपके UTF-8 टर्मिनल पर आज काम करता है, इसका मतलब यह नहीं है कि यह कल UTF-16 एन्कोडेड फ़ाइल पर काम करेगा। तो अब इसे सुरक्षित करें, और अपने उपयोगकर्ताओं के डेटा को ट्रैश करने के सिरदर्द से खुद को बचाएं!
यूनिकोड से निपटने का आसान हिस्सा आउटपुट और डिकोडिंग इनपुट है। कठिन हिस्सा आपके सभी इनपुट और आउटपुट को ढूंढ रहा है, और यह निर्धारित करता है कि यह कौन सा एन्कोडिंग है। लेकिन इसीलिए आपको मोटी रकम मिलती है :)