perl क्या एन्कोडिंग करता है एक फाइल के नाम पर readdir?



ubuntu encoding (1)

प्रश्न rephrased (जैसा मैं व्याख्या करता हूं) है:

क्यों नहीं readdir वापस नव निर्मित फ़ाइल नाम वापस आता है? (यहां, वेरिएबल filename द्वारा दर्शाया गया है जो कि Bärlauch सेट है)

(ध्यान दें: filename एक पर्ल निरंतर चर है, इसलिए यही कारण है कि इसके सामने $ Sigil गुम है।)

पृष्ठभूमि:

पहला नोट: आपके प्रोग्राम की शुरुआत में use utf8 स्टेटमेंट के कारण, filename को समयबद्ध करने पर यूनिकोड स्ट्रिंग में अपग्रेड किया जाएगा, क्योंकि इसमें गैर-एएससीआईआई वर्ण शामिल हैं। यूटीएफ 8 प्रोग्राम के दस्तावेज़ीकरण से:

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

और यह भी, Perluniintro अनुभाग "पर्ल के यूनिकोड मॉडल" के अनुसार :

सामान्य सिद्धांत यह है कि पर्ल अपने डेटा को यथासंभव लंबे समय तक आठ-बिट बाइट के रूप में रखने की कोशिश करता है, लेकिन जैसे ही यूनिकोडनेस से बचा नहीं जा सकता है, डेटा को पारदर्शी रूप से यूनिकोड में अपग्रेड किया गया है।

...

आंतरिक रूप से, पर्ल वर्तमान में यूनिटोड स्ट्रिंग्स को सांकेतिकृत करने के लिए प्लेटफॉर्म के मूल आठ-बिट वर्ण सेट (उदाहरण के लिए लैटिन-1), जो यूटीएफ -8 में चूक है, का उपयोग करता है।

filename में गैर- ASCII वर्ण अक्षर है। यदि आप आईएसओ 885 9-1 की विस्तारित एएससीआईआई एन्कोडिंग (लैटिन-1) का उपयोग करते हैं, तो यह बाइट मान 0xE4 रूप में एन्कोड किया गया है, इस तालिका को ascii-code.com पर ascii-code.com । हालांकि, अगर आपने filename से ä चरित्र को हटा दिया है, इसमें केवल एएससीआईआई वर्ण होंगे, और इसलिए इसे आंतरिक रूप से यूनिकोड में अपग्रेड नहीं किया जाएगा, भले ही आपने utf8 प्रोग्राम का इस्तेमाल किया हो।

इसलिए filename अब आंतरिक UTF-8 ध्वज सेट के साथ एक यूनिकोड स्ट्रिंग है ( UTF-8 फ्लैग के बारे में अधिक जानकारी के लिए utf8 pragma देखें) ध्यान दें कि अक्षर ä को दो बाइट्स 0xC3 0xA4 रूप में यूटीएफ -8 में एन्कोड किया गया है।

फाइल लेखन:

फ़ाइल लिखते समय, फ़ाइल नाम के साथ क्या होता है? यदि filename एक यूनिकोड स्ट्रिंग है, तो इसे यूटीएफ -8 के रूप में एन्कोड किया जाएगा। हालांकि, ध्यान दें कि filename पहले सांकेतिक शब्दों में बदलना आवश्यक नहीं है ( encode_utf8( filename ) )। अधिक जानकारी के लिए यूनिकोड वर्णों के साथ फ़ाइल नाम बनाना देखें। इसलिए फ़ाइल नाम यूटीएफ -8 एन्कोडेड बाइट के रूप में डिस्क पर लिखा है।

फ़ाइल नाम वापस पढ़ना:

जब फ़ाइल नाम वापस डिस्क से पढ़ने की कोशिश करते हैं, तो readdir यूनिकोड स्ट्रिंग (UTF-8 ध्वज सेट के साथ स्ट्रिंग्स) वापस नहीं करता है, भले ही फ़ाइल नाम UTF-8 में एन्कोड किए गए बाइट्स मौजूद हो। यह बाइनरी या बाइट स्ट्रिंग देता है, बाइट स्टॉर्ड्स बनाम कैरेक्टर (यूनिकोड) स्ट्रिंग्स की चर्चा के लिए पेर्लुनिटट देखें।

क्यों नहीं readdir यूनिकोड स्ट्रिंग्स वापसी? सबसे पहले, पेर्नल्यूनोड अनुभाग के अनुसार "जब यूनिकोड नहीं होता है" :

अब भी कई जगह हैं जहां यूनिकोड (कुछ एन्कोडिंग में या किसी अन्य) को तर्क के रूप में दिया जा सकता है या परिणाम के रूप में प्राप्त किया जा सकता है, या पर्ल में दोनों हो सकता है, लेकिन ऐसा नहीं है। (...)

निम्नलिखित ऐसे इंटरफेस हैं इन सभी इंटरफेस पर्ल के लिए वर्तमान में (v5.16.0 के रूप में) केवल तर्क और परिणाम दोनों के रूप में बाइट स्ट्रिंग मानता है। (...)

एक कारण यह है कि पर्ल इन स्थितियों में यूनिकोड की भूमिका को हल करने का प्रयास नहीं करता है कि उत्तर ऑपरेटिंग सिस्टम और फाइल सिस्टम पर अत्यधिक निर्भर हैं। उदाहरण के लिए, क्या फाइलनाम यूनिकोड में हो सकते हैं और वास्तव में किस तरह की एन्कोडिंग में, यह वास्तव में एक पोर्टेबल अवधारणा नहीं है (...)

  • chdir, chmod, chown, chroot, exec, link, lstat, mkdir, rename, rmdir, - स्टेट, सिमलिंक, ट्रुनकेट, अनलिंक, यूटीएमई, -एक्स
  • % ENV
  • ग्लोब (उर्फ <*>)
  • खुला, ऑपेनिर, सिसोपन
  • क्यूक्स (बैकटीक ऑपरेटर उर्फ), सिस्टम
  • readdir, readlink

इसलिए readdir बाइट स्ट्रिंग्स रिटर्न करता है, चूंकि यह फ़ाइल नाम के एन्कोडिंग को प्राथमिकता से जानना सामान्य रूप से असंभव है पृष्ठभूमि की जानकारी के लिए क्यों यह असंभव है, उदाहरण के लिए देखें:

स्ट्रिंग तुलना:

अब, अंत में आप फ़ाइल $filename_read साथ $filename_read नाम $filename_read तुलना करने का प्रयास करते हैं:

print "found\n" if $filename_read eq filename;

इस मामले में केवल $filename_read और filename बीच अंतर है कि $filename_read में UTF-8 ध्वज सेट नहीं है (यह पर्ल आंतरिक रूप से "यूनिकोड स्ट्रिंग" के रूप में पहचान नहीं करता है)।

दिलचस्प बात यह है कि eq ऑपरेटर का नतीजा इस पर निर्भर करेगा कि $filename_read में बाइट शुद्ध ASCII है या नहीं। इनोडोड मॉड्यूल के प्रलेखन के अनुसार:

पर्ल में यूनिकोड समर्थन की शुरूआत करने से पहले, eq ऑपरेटर सिर्फ स्ट्रेंल्स की तुलना में दो स्केलरों के प्रतिनिधित्व करते हैं। पर्ल 5.8 के साथ शुरुआत, eq दो स्ट्रिंग्स को यूटीएफ 8 ध्वज के साथ-साथ विचार के साथ तुलना करता है।

...

जब आप डीकोड करते हैं, तो परिणामस्वरूप यूटीएफ 8 ध्वज चालू होता है - जब तक कि आप डेटा को निर्विवाद रूप से प्रदर्शित नहीं कर सकते

इसलिए आपके मामले में, eq UTF-8 ध्वज पर विचार करेगा क्योंकि $file_name_read में शुद्ध एएससीआईआई नहीं है, और इसके परिणामस्वरूप यह दो स्ट्रिंग के समान नहीं होगा । अगर $filename_read और filename जहां समान और केवल शुद्ध ASCII बाइट (और filename अभी भी UTF-8 ध्वज सेट था, $filename_read में UTF-8 झंडा सेट नहीं था), तो eq दोनों तारों को समान मानता है। इस व्यवहार के लिए पृष्ठभूमि के बारे में अधिक जानकारी Encode के लिए दस्तावेज़ में चर्चा करें।

निष्कर्ष:

इसलिए यदि आप सापेक्ष आश्वस्त हैं कि आपके सभी फ़ाइल नाम यूटीएफ -8 एन्कोडेड हैं, तो आप अपने प्रश्न में readdir स्ट्रिंग (यूटीएफ -8 ध्वज सेट करने के लिए मजबूर) में readdir से लौटे बाइट स्ट्रिंग को डिकोड करके इस समस्या को हल कर सकते हैं:

$filename_read = Encode::decode_utf8( $filename_read );

अधिक जानकारी

नोट: चूंकि यूनिकोड एक ही अक्षर के कई अभ्यावेदनों की अनुमति देता है, वहां बार्लोच में ä (लेटिन छोटे अक्षर ए के साथ संयोजन वाले डायरेसिस) के दो रूप मौजूद हैं। उदाहरण के लिए,

  • यू + 00 ई 4 एनएफसी (सामान्यकरण फॉर्म कैनोनिकल रचना) प्रपत्र है,
  • यू + 0061.0308 एनएफडी (सामान्यीकृत फॉर्म कैननिकल अपघटन) फार्म है।

मेरे प्लेटफार्म (लिनक्स) पर, यूटीएफ -8 एन्कोडेड फाइलनाम एनएफसी फॉर्म के जरिए जमा होते हैं, लेकिन मैक ओएस पर वे एनएफडी फॉर्म का उपयोग करते हैं अधिक जानकारी के लिए Encode::UTF8Mac देखें। इसका मतलब यह है कि यदि आप लिनक्स मशीन पर काम करते हैं, और उदाहरण के लिए एक मैक उपयोगकर्ता द्वारा बनाए गए एक गीट भंडार क्लोन करते हैं, तो आप आसानी से अपने लिनक्स मशीन पर एनएफडी एन्कोडेड फ़ाइल नाम पा सकते हैं। इसलिए लिनक्स फाइल सिस्टम पर कोई परवाह नहीं है कि फ़ाइल नाम किस एन्कोडिंग में है; यह सिर्फ बाइट्स के अनुक्रम के रूप में सोचता है। इसलिए, मैं आसानी से एक स्क्रिप्ट लिख सकता हूं जो आईएसओ-लैटिन -1 एन्कोडेड फ़ाइल नाम का निर्माण करती थी, भले ही मेरा लोकेल "en_US.UTF-8" । वर्तमान लोकेल सेटिंग केवल अनुप्रयोगों के लिए दिशानिर्देश हैं, लेकिन यदि एप्लिकेशन लोकेल सेटिंग को अनदेखा कर देती है तो ऐसा कुछ भी नहीं है जो उन्हें ऐसा करने से रोक देता है

इसलिए अगर आप अनिश्चित हैं कि अगर readdir से फ़ाइल नाम वापस एनएफसी या एनएफडी का उपयोग कर रहे हैं, तो आपको हमेशा उसे डीकोड करने के बाद सिकोड़ना चाहिए:

use Unicode::Normalize;
print "found\n" if NFD( $filename_read ) eq NFD( filename );

पर्ल यूनिकोड कुकबुक अनुभाग "हमेशा सिकुड़ें और फिर से करें" देखें

अंत में, यह जानने के लिए कि कैसे लोकेल पर्ल में यूनिकोड के साथ मिलकर काम करता है, आप इसे देख सकते हैं:

यहाँ एक पर्ल स्क्रिप्ट है जो मुझे निष्पादित होने पर found कि प्रिंट करना अपेक्षित है:

#!/usr/bin/perl
use warnings;
use strict;
use utf8;
use Encode;

use constant filename => 'Bärlauch';

open (my $out, '>', filename) or die;
close $out;

opendir(my $dir, '.') or die;
while (my $filename_read = readdir($dir)) {
# $filename_read = encode('utf8', $filename_read);
  print "found\n" if $filename_read eq filename;
}

स्क्रिप्ट पहले फ़ाइल नाम के साथ लगातार filename नाम बनाता है। (स्क्रिप्ट चलाने के बाद, मैं फाइल के अस्तित्व को ls साथ सत्यापित कर सकता हूं और फ़ाइल "अजीब" वर्णों के साथ नहीं बनाई गई है।)

फिर स्क्रिप्ट वर्तमान कार्य निर्देशिका में फाइलों को पुनरावृत्त करती है और प्रिंट found यदि कोई ऐसी फ़ाइल है जिसका नाम फ़ाइल के बराबर है जिसे अभी बनाया गया है। यह स्पष्ट रूप से मामला होना चाहिए।

हालांकि, यह (उबंटू, बाश, LANG=en_US.UTF8 ) नहीं है

अगर मैं निरंतर निरंतर Barlauch को Barlauch , तो यह अपेक्षित काम करता है और found

$filename_read = encode('utf8', $filename_read); uncommenting $filename_read = encode('utf8', $filename_read); व्यवहार को बदल नहीं करता है

क्या इस बात के लिए एक स्पष्टीकरण है और इसमें उम्मुट के साथ फाइल नाम को पहचानने के लिए मुझे क्या करना होगा?





character-encoding