
एक आम गलतफहमी यह है कि चरित्र के तार बाइट स्ट्रिंग्स के विपरीत, यूटीएफ -8 ध्वज सेट है।
कई लोगों को संदेह है कि अगर डेटा ASCII-7-bit है, तो UTF-8 ध्वज बस महत्वपूर्ण नहीं है।
हालांकि, वास्तव में, इसे सेट या रीसेट किया जा सकता है, दोनों प्रतीकों के लिए और बिल्कुल मनमाना बाइनरी डेटा के लिए।
जाने-माने पर्ल समुदाय लेखक
मार्क लेहमैन इस पर
JSON :: XS मॉड्यूल प्रलेखन में टिप्पणी करते हैं।
आपके पास उस ध्वज सेट के साथ यूनिकोड के तार हो सकते हैं, उस ध्वज के साथ स्पष्ट, और आपके पास उस ध्वज सेट और उस ध्वज के साथ बाइनरी डेटा हो सकता है। अन्य संभावनाएं भी मौजूद हैं।
उस मामले पर विचार करें जहां ASCII-7bit डेटा में UTF-8 ध्वज सेट है।
use utf8; use strict; use warnings; my $u = "";
यह कोड "UTF-8 ध्वज सेट!" प्रदर्शित करता है। यही है, विभाजन ऑपरेशन के बाद यूनिकोड स्ट्रिंग (UTF-8 ध्वज के साथ) को भागों में विभाजित करने के बाद ASCII-7bit स्ट्रिंग को यह ध्वज प्राप्त हुआ। हम यह कह सकते हैं कि प्रोग्रामर यह नियंत्रित नहीं करता है कि उसके ASCII डेटा में UTF-8 ध्वज होगा या नहीं, यह इस बात पर निर्भर करता है कि डेटा कहाँ और कैसे प्राप्त किया गया था, और इसके आगे क्या डेटा था।
यदि आप ASCII-7bit वर्णों को ASCII-7bit वर्णों में कूटबद्ध करते हुए कूटबन्धन का उपयोग करते हैं तो समान प्रभाव प्राप्त होता है।
use strict; use warnings; use Encode; my $ascii = 'x';
यानी राउंड-ट्रिप ट्रांसकोडिंग डेटा को बदलता नहीं है (यह अपेक्षित है), लेकिन UTF-8 ध्वज को सेट करता है।
(हालाँकि, डिकोड का यह व्यवहार) अपने स्वयं के
प्रलेखन का खंडन करता है, जो बदले में, इस विचार का खंडन करता है कि ASCII डेटा में utf-8 ध्वज के संबंध में कोई प्रलेखन और गारंटी नहीं होनी चाहिए)
UTF-8 ध्वज की उपस्थिति के कारणों को दक्षता के विचार से समझाया जा सकता है। यह देखने के लिए एक स्ट्रिंग को पार्स करने के बाद बहुत महंगा है यह देखने के लिए कि क्या इसमें केवल ASCII वर्ण हैं, और क्या ध्वज को रीसेट किया जा सकता है।
UTF-8 ध्वज का यह व्यवहार वायरस के समान है - यह उन सभी डेटा को संक्रमित करता है जिनके संपर्क में यह आता है।
उस मामले पर विचार करें जहां गैर-एएससीआईआई, यूनिकोड वर्णों में यूटीएफ -8 ध्वज नहीं है।
use strict; use warnings; use Digest::SHA qw/sha1_hex/; use utf8; my $s = "µ"; my $s1 = $s; my $s2 = $s; my $digest = sha1_hex($s2);
प्रिंट:
utf-8 बिट ऑन (s1)
s1 और s2 बराबर हैं
यही है, तीसरे पक्ष के मॉड्यूल के फ़ंक्शन कॉल ने UTF-8 ध्वज को गिरा दिया। इसी समय, ध्वज के साथ और उसके बिना रेखाएं पूरी तरह से समान थीं।
यह केवल वर्ण> 127 और <= 255 (यानी लैटिन -1) के साथ हो सकता है।
वास्तव में, ऑपरेशन
utf8 :: डाउनग्रेड स्ट्रिंग $ s2 के साथ हुआ है
इस फ़ंक्शन को एक स्ट्रिंग के आंतरिक प्रतिनिधित्व को बदलने के रूप में
प्रलेखन में वर्णित किया गया है:
देशी इनकोडिंग (लैटिन -1 या EBCDIC) में बराबर ऑक्टेट अनुक्रम के लिए UTF-X से स्ट्रिंग के आंतरिक प्रतिनिधित्व को सम्मिलित करता है। तार्किक चरित्र क्रम स्वयं अपरिवर्तित है।
सिद्धांत रूप में, डाइजेस्ट :: SHA मॉड्यूल इस व्यवहार का दस्तावेजीकरण करता है, हालांकि इसके लिए आवश्यक नहीं है:
ज्ञात हो कि डाइजेस्ट रूटीन चुपचाप UTF-8 इनपुट को इसके में बदल देता है
देशी एन्कोडिंग में बराबर बाइट अनुक्रम (cf. utf8 :: डाउनग्रेड)। यह
साइड इफेक्ट केवल उसी तरह प्रभावित करता है जिस तरह पर्ल डेटा को आंतरिक रूप से संग्रहीत करता है, लेकिन
अन्यथा डेटा का वास्तविक मूल्य बरकरार रहता है।
सामान्य स्थिति में, कोई भी 3-rd पार्टी फ़ंक्शन डॉक्यूमेंट में सूचित किए बिना स्ट्रिंग्स को डाउनग्रेड कर सकता है (या, उदाहरण के लिए, इसे कभी-कभार ही करें)।
मामले पर विचार करें जब बिल्कुल मनमाना, बाइनरी डेटा में एक UTF-8 ध्वज होता है।
use utf8; use strict; use warnings;
बाहर देता है:
मूल बिन की लंबाई: 3 3
bin_a लंबाई: 4 4
बिन_उ की लंबाई: 4 7
bin_a और bin_u बराबर हैं!
33818f4b23aa74cddb8eb625845a459a file_a.tmp
33818f4b23aa74cddb8eb625845a459a file_u.tmp
परिणामस्वरूप, यह पता चलता है कि बाइनरी डेटा, एएससीआईआई स्ट्रिंग के साथ समवर्ती होने के बाद, बाइट्स में आंतरिक आकार में वृद्धि हुई है (लेकिन वर्णों में नहीं) 4 से 7 तक, लेकिन केवल अगर, बिना अर्थ के, यूटीएफ -8 ध्वज ASCII द्वारा सेट किया गया था ।
हालाँकि, जब इस डेटा की एक दूसरे से तुलना करते हैं, तो वे समान होते हैं, दोनों लाइनों को फ़ाइल में आउटपुट करते समय, एन्कोडिंग निर्दिष्ट किए बिना भी, फ़ाइलें भी समान थीं।
इस प्रकार, द्विआधारी डेटा आकार में बढ़ सकता है और एक UTF-8 ध्वज प्राप्त कर सकता है, जबकि कोई बग नहीं है, सभी अंतर्निहित पर्ल फ़ंक्शन उन्हें ठीक उसी तरह संसाधित करते हैं जैसे कि कोई झंडा नहीं था (यदि अपवाद हैं, तो बग उनमें है)।
किसी भी अन्य पर्ल कोड को भी ऐसे डेटा को त्रुटियों के बिना संसाधित करना चाहिए (यदि यह स्ट्रिंग की आंतरिक संरचना का विश्लेषण करने की कोशिश नहीं करता है, या कम से कम इसे सही ढंग से पार्स करता है)
वास्तव में, द्विआधारी डेटा का क्या हुआ यह
utf8 के अनुरूप है
:: अपग्रेड ऑपरेशन। डेटा को लैटिन -1 के रूप में व्याख्या किया गया था, जिसे यूटीएफ -8 में बदल दिया गया था, और यूटीएफ -8 ध्वज को सेट किया गया था। यह ऑपरेशन
utf8 के विपरीत है
:: डाउनग्रेड ऊपर वर्णित है।
utf8 :: डाउनग्रेड केवल लैटिन -1 वर्णों के साथ किया जा सकता है। और
utf8 :: उन्नयन किया जा सकता है
किसी भी बाइट के साथ (चूंकि कोई भी बाइट लैटिन -1 से एक चरित्र से मेल खाता है)।
यह महत्वपूर्ण हो सकता है यदि आपके पास आपकी मेमोरी में बाइनरी डेटा की एक बड़ी मात्रा है। अगर 400 मेगाबाइट की बूँद अचानक 700 मेगाबाइट में बदल जाती है, तो यह बिल्कुल भी अच्छा नहीं है, क्योंकि आपने वहां पर UTF-8 फ्लैग के साथ एक ASCII-7bit बाइट जोड़ी है। इस स्थिति से बाहर निकलने का एक अच्छा तरीका यूनिट टेस्ट या यूटीएफ -8 फ्लैग चेक के साथ रनटाइम
एसेसरीज है ।
सामान्य तौर पर, वर्णों से बाइट को अलग करना संभव नहीं है
समस्या पर विचार करें: एक फ़ंक्शन लिखें जिसमें XML इनपुट होगा, यदि XML बाइट्स है, तो "xml" टैग में एन्कोडिंग को देखें और उन्हें वर्णों में एनकोड करें। यदि यह पहले से ही प्रतीक हैं, तो कुछ भी न करें।
इस तरह के समारोह को लागू नहीं किया जा सकता है। उदाहरण के लिए, वर्ण स्ट्रिंग "हैलो, म्युचेन" के लिए, फ़ंक्शन नहीं कर सकता
इस वर्ण, या बाइट्स को CP1251, या KOI8-R में (स्ट्रिंग के डाउनग्रेड होने की स्थिति में, और यह प्रोग्रामर आमतौर पर नियंत्रित नहीं करता है) के बीच अंतर करने के लिए।
वर्ण> 255 के लिए, UTF-8 ध्वज हमेशा सेट होता है (आप उनके साथ
utf8 :: डाउनग्रेड का उपयोग नहीं कर सकते हैं)। कोड के साथ वर्णों के लिए <= 127 UTF-8, बिट महत्वपूर्ण नहीं है, इस अर्थ में कि उन्हें बाइनरी डेटा और वर्ण दोनों माना जा सकता है। लैटिन 1 वर्णों के लिए, बाइट्स से अंतर करना संभव नहीं है।
पर्ल में पात्रों से विशिष्ट बाइट्स एक ईमेल से और एक व्यक्ति के नाम से एक फ़ाइल नाम को भेद करने के समान है। कभी-कभी यह संभव है, लेकिन सामान्य मामले में, नहीं। प्रोग्रामर को स्वयं याद रखना चाहिए कि उसके पास कौन सा चर है।
यह दस्तावेज में है:
perldoc.perl.org/perlunifaq.htmlमैं यह कैसे निर्धारित कर सकता हूं कि एक स्ट्रिंग एक पाठ स्ट्रिंग या एक बाइनरी स्ट्रिंग है?
आप नहीं कर सकते। कुछ इसके लिए UTF8 ध्वज का उपयोग करते हैं, लेकिन यह दुरुपयोग है, और डेटा जैसे अच्छे व्यवहार करता है मॉड्यूल :: डम्पर खराब दिखते हैं। इस उद्देश्य के लिए ध्वज बेकार है, क्योंकि जब स्ट्रिंग को संग्रहीत करने के लिए 8 बिट एन्कोडिंग (डिफ़ॉल्ट आईएसओ-8859-1 द्वारा) का उपयोग किया जाता है तो यह बंद हो जाता है।
यह कुछ आप है, प्रोग्रामर, का ट्रैक रखना है; माफ़ कीजिए। आप इसके साथ मदद करने के लिए "हंगेरियन नोटेशन" को अपनाने पर विचार कर सकते हैं।
यदि आपको अभी भी ऐसा करने की आवश्यकता है, तो आप अपनी खुद की कक्षा बना सकते हैं, जिसमें बाइट्स या वर्णों का एक स्ट्रिंग होगा, और एक ध्वज जो यह दिखाएगा कि (उसी चाल ईमेल बनाम फ़ाइल नाम बनाम व्यक्ति के नाम के लिए उपयुक्त है)।
लैटिन -1 के पात्रों के लिए व्यापक वर्ण जारी नहीं किए गए हैं
निम्न उदाहरण चेतावनी को केवल तब
प्रिंट करता है जब हम $ s2 प्रिंट करते हैं
use strict; use warnings; use utf8; my $s1 = "ß"; my $s2 = ""; my $s = $ARGV[0] ? $s1 : $s2; print $s;
यदि हम $ s1 प्रिंट करते हैं, तो पर्ल यूनिकडे वर्ण U (U + 00DF, UTF-8 \ xC3xF9) को बाइट \ xDF में परिवर्तित करता है और इसे प्रदर्शित करने का प्रयास करता है।
समान कार्य सभी कार्यों के लिए सही है जो बाइट स्वीकार करते हैं, वर्ण नहीं (एन्कोडिंग निर्दिष्ट करने के बिना प्रिंट, syswrite, चेकसम SHA, MD5, CRC32, MIME :: Base64)।
वायरल डाउनग्रेड
लेख की शुरुआत में, ASCII वर्णों में UTF-8 बिट के "वायरल" व्यवहार का वर्णन किया गया था (वायरल
utf8 :: उन्नयन )। अब लैटिन -1 अक्षरों
(UTF8 :: डाउनग्रेड ) में UTF-8 बिट के "वायरल" रीसेट पर विचार करें।
कल्पना करें कि हम एक फ़ंक्शन लिख रहे हैं जो केवल बाइट्स पर परिभाषित है, और वर्णों पर नहीं, हैश फ़ंक्शन, एन्क्रिप्शन, संग्रह, माइम :: बेस 64, आदि एक अच्छा उदाहरण हैं।
1. चूंकि द्विआधारी डेटा को वर्णों से अलग करना असंभव है, इसलिए आपको इनपुट को बाइट्स मानना चाहिए।
2. बाइट्स में एक
अपग्रेड फॉर्म हो सकता है (जैसे UTF-8 फ्लैग के साथ)। परिणाम
डाउनग्रेड फॉर्म के समान होना चाहिए।
इसलिए, आपको
utf8 :: डाउनग्रेड करने की आवश्यकता है और यदि यह काम नहीं करता है तो एक त्रुटि फेंक दें।
एल्गोरिदम, जैसे कि हैश फ़ंक्शंस, प्रदर्शन के लिए चिंता की विशेषता है। स्मृति में डेटा की दूसरी प्रतिलिपि बनाना कुशल नहीं है, इसलिए, ज्यादातर मामलों में, फ़ंक्शन इसमें पारित पैरामीटर को संशोधित करता है।
जैसा कि कई लोग शायद जानते हैं, पर्ल में सभी पैरामीटर संदर्भ द्वारा पारित किए जाते हैं, लेकिन आमतौर पर मूल्य द्वारा उपयोग किया जाता है।
sub mycode { $_[0] = "X";
sub mycode { my ($arg1) = @_;
इस प्रकार, जब पर्ल स्पेसिफिकेशन के अनुसार काम करने वाला कोड बनाया जाता है, तो कोड बनाया जाता है जो चुपचाप
utf8 करता है
:: कॉल करने वाले की इच्छा की परवाह किए बिना वास्तविक मापदंडों पर
डाउनग्रेड , जिससे संभवतः किसी अन्य स्थान पर बग का निर्माण हो सकता है गलत तरीके से संसाधित लाइनें, और इस बिंदु तक ठीक काम किया।
फ़ाइल नामों के लिए, यह काम नहीं करता है
फ़ाइल नाम को तर्क (
खुले , फ़ाइल परीक्षण
-X ) के साथ-साथ फ़ाइल नाम (
रीडडीर ) के रूप में स्वीकार करने वाले फ़ंक्शंस इन नियमों का पालन नहीं करते हैं (यह प्रलेखन में
नोट किया गया है)।
वे केवल फ़ाइल नाम की व्याख्या करते हैं क्योंकि यह स्मृति में है।
उनके काम के एल्गोरिदम को निम्नानुसार वर्णित किया जा सकता है:
sub open { my ( ... $filename) = @_; utf8::_utf8_off($filename);
इसके कई कारण हैं:
1. कई POSIX सिस्टम (लिनक्स / * BSD) में, कई फाइल सिस्टम पर, फ़ाइल का नाम बाइट्स का एक मनमाना अनुक्रम हो सकता है, जरूरी नहीं कि किसी भी एन्कोडिंग में वर्णों का अनुक्रम हो।
2. फ़ाइल सिस्टम के एन्कोडिंग को निर्धारित करने का कोई पोर्टेबल तरीका नहीं है।
3. मशीन पर विभिन्न एन्कोडिंग के साथ कई फाइल सिस्टम हो सकते हैं
4. आप इस धारणा पर भरोसा नहीं कर सकते कि फ़ाइल नामों की एन्कोडिंग लोकेल के एन्कोडिंग से मेल खाती है।
5. पुराने कोड के साथ संगत होना चाहिए।
नतीजतन, प्रोग्रामर को एन्कोडिंग निर्धारित करना चाहिए और इसे दुभाषिया से संवाद करना चाहिए, लेकिन इसके लिए एपीआई अभी तक नहीं किया गया है।
हम अपने उदाहरण को संशोधित करते हैं जहां हम "गलती से" एक डाउनग्रेड चरित्र स्ट्रिंग पर ठोकर खाई।
use strict; use warnings; use Digest::SHA qw/sha1_hex/; use utf8; my $s = "µ"; my $s1 = $s; my $s2 = $s; my $digest = sha1_hex($s2);
काम का परिणाम:
s1 और s2 बराबर हैं
s2 विफल: ऐसी कोई फ़ाइल या निर्देशिका नहीं है
यानी लाइनें s1 और s2 संयोग करती हैं, लेकिन अलग-अलग फ़ाइलों की ओर
इशारा करती हैं , यदि
sha1_hex निष्कासन हटाया
जाता है, तो उसी फ़ाइलों में।
आप फ़ाइलों के साथ काम करने वाले किसी भी मॉड्यूल का उपयोग करके उसी रेक पर ठोकर खा सकते हैं (उदाहरण के लिए,
फ़ाइल :: ढूंढें )
जब दूसरा काम नहीं करता है
एनकोड मॉड्यूल में, एक
डीकोड_utf8 फ़ंक्शन होता है
इस रूप में प्रलेखित:
$ String = decode ("utf8", $ octets [, CHECK]) के बराबर
लेकिन वास्तव में, यदि यूटीएफ -8 को $ ओकटेट्स पर सेट किया जाता है, तो फ़ंक्शन बस उन्हें अपरिवर्तित लौटाता है (हालांकि इसे
utf8 :: डाउनग्रेड बनाने की कोशिश करनी चाहिए और उनके साथ द्विआधारी डेटा की तरह काम करना चाहिए, और यदि
डाउनग्रेड विफल रहता है, तो एक
वाइड वर्ण त्रुटि फेंकें) ।
इस बग को देखा गया था (
RT # 61671 RT # 87267 ) जैसे ही यह दिखाई दिया - 2010 में।
लेकिन अनुचर ऐसी सभी बग रिपोर्ट को खारिज कर देता है। इसके अलावा, रिपोर्ट का सार यह भी नहीं है कि फ़ंक्शन सही ढंग से व्यवहार करता है (पर्ल के विचार के अनुसार), और यह भी नहीं कि इस व्यवहार का वर्णन करने के लिए प्रलेखन था, लेकिन यह, कम से कम, यह व्यवहार नहीं है मौजूदा प्रलेखन के विपरीत होना चाहिए। Meinteiner का मानना है कि कार्यों को समकक्ष के रूप में प्रलेखित किया गया है, और इसका मतलब समान नहीं है (हालांकि मेरी राय में, समानता को समानता और पहचान के रूप में माना जा सकता है)। शायद गणित में, समतुल्यता भी पहचान का संकेत नहीं है ... अगर कोई इस पहेली को हल कर सकता है, तो मैं बहुत आभारी रहूंगा।
यूनिकोड बग
डाउनग्रेड किए गए फॉर्म में, लैटिन -1 को बाइट्स से अलग नहीं किया जा सकता है, इसलिए, इस फॉर्म में, कुछ
मेटाचैकर्स नियमित अभिव्यक्तियों में, फ़ंक्शन
uc ,
lc ,
quotemeta ,
अच्छी तरह से काम नहीं करते
हैं ।
वर्कअराउंड
utf8 :: उन्नयन है , या, पर्ल के नए संस्करणों में, कुछ निर्देश हैं जो इस व्यवहार को सुसंगत बनाते हैं।
पर्ल दस्तावेज़ में विस्तृत विवरण
इस सबका क्या करना है?
1. उपयोग न करें (जब तक कि आपको पता नहीं है कि आप क्या कर रहे हैं) निम्न कार्य करता है:
utf8 :: is_utf8 ,
Encode :: _ utf8_on ,
Encode :: _ utf8_off , और
बाइट्स मॉड्यूल से सभी कार्य (इन सभी कार्यों के लिए प्रलेखन उनके उपयोग की अनुशंसा नहीं करता है, सिवाय डिबगिंग के लिए)
2. उपयोग
utf8 :: उन्नयन ,
utf8 :: डाउनग्रेड , जब भी पर्ल विनिर्देशन की आवश्यकता होती है
3. वर्णों से बाइट्स में परिवर्तित करने के लिए,
एनकोड :: एनकोड ,
एनकोड :: डिकोड का उपयोग करें3. यदि आप किसी और के कोड का उपयोग करते हैं जो इन नियमों का उल्लंघन करता है, तो इसे बग के लिए जांचें, वर्कअराउंड का उपयोग करें।
4. फ़ाइल नामों के साथ काम करते समय, आपको या तो सभी कार्यों पर आवरण का उपयोग करना होगा, या, परीक्षणों का उपयोग करके, यह सुनिश्चित करें कि कोड के काम के दौरान फ़ाइल नामों का आंतरिक प्रतिनिधित्व नहीं बदलता है।
ऐसे कई उदाहरण हैं जहां इन नियमों का उल्लंघन मुझे उचित लगा।
Encode::_utf8_off($_[0]) if utf8::is_utf8($_[0]) && (bytes::length($_[0]) == length($_[0]));
(ASCII-7bit पाठ के लिए UTF-8 ध्वज को साफ़ करेगा (जिससे 5.19 को छोड़कर सभी Perl में regexp प्रदर्शन में 30% वृद्धि प्राप्त होगी)
defined($_[0]) && utf8::is_utf8($_[0]) && (bytes::length($_[0]) != length($_[0]))
(यदि TRU में UTF-8 ध्वज सेट है तो यह TRUE लौटाता है और यह ASCII-7bit नहीं है। इसका उपयोग यूनिट परीक्षणों में किया जा सकता है ताकि यह सुनिश्चित किया जा सके कि आपके 400 मेगाबाइट के बाइनरी डेटा 700 में बदल न जाएं)
कुछ न करने का एक और विकल्प है। ईमानदारी से, किसी भी बग पर आने से पहले आपको काफी समय लगेगा (लेकिन तब तक बहुत देर हो चुकी होगी)। यह विकल्प लाइब्रेरी डेवलपर्स के लिए अत्यधिक अनुशंसित है।