खोज…


टिप्पणियों

फाइलिंग एन्कोडिंग पर चेतावनी


यह उल्लेखनीय है कि फाइलनेम एनकोडिंग न केवल प्लेटफॉर्म विशिष्ट है, बल्कि फाइलसिस्टम विशिष्ट भी है।

यह मान लेना कभी भी पूरी तरह से सुरक्षित नहीं है (लेकिन अक्सर आमतौर पर) यह है कि सिर्फ इसलिए कि आप किसी दिए गए फ़ाइलनाम को एन्कोड और लिख सकते हैं, कि जब आप बाद में पढ़ने के लिए उसी फ़ाइल नाम को खोलने का प्रयास करते हैं, तो यह अभी भी उसी चीज को कहा जाएगा।

उदाहरण के लिए, यदि आप एक फाइल सिस्टम जैसे कि FAT16 लिखते हैं जो यूनिकोड का समर्थन नहीं करता है, तो आपके फ़ाइलनाम चुपचाप ASCII- संगत रूपों में अनुवादित हो सकते हैं।

लेकिन यह मान लेना भी कम सुरक्षित है कि स्पष्ट नामकरण द्वारा आप जिस फ़ाइल को बना सकते हैं, पढ़ सकते हैं और लिख सकते हैं, वही कॉल तब की जाएगी जब अन्य कॉल के माध्यम से क्वेरी की जाती है, उदाहरण के लिए, readdir आपके फ़ाइल नाम के लिए अलग-अलग बाइट्स लौटा सकता है, जिसे आपने open लिए निर्दिष्ट किया था ।

VAX जैसे कुछ सिस्टमों पर, आप हमेशा यह नहीं मान सकते हैं कि readdir वही फ़ाइलनाम लौटाएगा जिसे आप फ़ाइलनाम के लिए open रूप में foo.bar रूप में foo.bar , क्योंकि फ़ाइल एक्सटेंशन को OS द्वारा foo.bar जा सकती है।

इसके अलावा, UNIX पर, फ़ाइलनामों के लिए कानूनी वर्णों का एक बहुत ही उदार सेट है जो OS अनुमति देता है, केवल / और \0 को छोड़कर, जहाँ विंडोज़ पर, वर्णों की विशिष्ट श्रृंखलाएँ होती हैं जो फ़ाइल नाम में निषिद्ध हैं और त्रुटियों का कारण बनेंगी।

फ़ाइल नामों के साथ यहां ज्यादा सावधानी बरतें, से बचने के फैंसी चाल यदि आप एक विकल्प है, और हमेशा यकीन है कि किसी भी फैंसी चाल आप उपयोग संगत कर रहे हैं ऐसा करने के लिए परीक्षण किया है।

अगर आपका लेखन कोड ऐसी है कि लिए करना है तो लेखन कोड के रूप में यदि आप अपने नियंत्रण से बाहर प्लेटफ़ॉर्म पर चलने के लिए लक्षित बहुत सावधानी के रूप में दोगुना व्यायाम CPAN , और मान अपने उपयोगकर्ता आधार का कम से कम 5% कुछ का उपयोग कर अटक हो जाएगा प्राचीन या टूटी हुई तकनीक, या तो दुर्घटना से, या उनके नियंत्रण से बाहर की शक्तियों द्वारा, और ये कि उनके लिए बग बनाना होगा।

: एन्कोडिंग (utf8) बनाम: utf8


चूंकि UTF-8 पर्ल में तारों के प्रतिनिधित्व के लिए आंतरिक स्वरूपों में से एक है, इसलिए एन्कोडिंग / डिकोडिंग कदम को अक्सर छोड़ दिया जा सकता है। इसके बजाय :encoding(utf-8) , आप बस उपयोग कर सकते हैं :utf8 , यदि आपका डेटा पहले से ही UTF-8 में है। :utf8 को आउटपुट स्ट्रीम के साथ सुरक्षित रूप से उपयोग किया जा सकता है, जबकि इनपुट स्ट्रीम के लिए यह खतरनाक हो सकता है, क्योंकि यह आंतरिक असंगतता का कारण बनता है जब आपके पास अमान्य बाइट अनुक्रम होते हैं। इसके अलावा, इनपुट के लिए :utf8 का उपयोग सुरक्षा भंग हो सकता है, इसलिए :encoding(utf-8) का उपयोग उचित है।

अधिक विवरण: एन्कोडिंग और: utf8 के बीच अंतर क्या है

UTF-8 बनाम utf8 बनाम UTF8


पर्ल v5.8.7 , "UTF-8" (डैश के साथ) का अर्थ है UTF-8 अपने सख्त और सुरक्षा-सचेत रूप में, जबकि "utf8" अर्थ है UTF-8 अपने उदार और ढीले रूप में।

उदाहरण के लिए, "utf8" का उपयोग कोड बिंदुओं के लिए किया जा सकता है जो कि यूनिकोड में मौजूद नहीं है, जैसे 0xFFFFFFFF । इसके विपरीत, अमान्य UTF-8 बाइट सीक्वेंस जैसे "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}" एक में डिकोड हो जाएगा अमान्य यूनिकोड (लेकिन वैध पर्ल) कोडपॉइंट ( 0xFFFFFFFF ) का उपयोग करते समय "utf8" , जबकि "UTF-8" एन्कोडिंग वैध यूनिकोड की श्रेणी से बाहर करने के लिए कोड पॉइंट्स डिकोडिंग की अनुमति नहीं होगी और आप एक प्रतिस्थापन चरित्र (देना होगा 0xFFFD ) के बजाय।

चूंकि एन्कोडिंग नाम केस असंवेदनशील हैं, इसलिए "UTF8" "utf8" (यानी गैर-सख्त संस्करण) के समान है।

अधिक जानकारी: UTF-8 बनाम utf8 बनाम UTF8

अधिक पढ़ना


पर्ल के यूनिकोड हैंडलिंग के बारे में विवरण निम्नलिखित स्रोतों में अधिक विस्तार से वर्णित है:

Stackoverflow.com से पोस्ट (चेतावनी: अद्यतित नहीं हो सकती है):

Youtube वीडियो:

फ़ाइल नाम बनाएँ

निम्न उदाहरण डिस्क पर फ़ाइलनाम (और निर्देशिका नाम) का प्रतिनिधित्व करने के लिए UTF-8 एन्कोडिंग का उपयोग करते हैं। यदि आप किसी अन्य एन्कोडिंग का उपयोग करना चाहते हैं, तो आपको Encode::encode(...) उपयोग करना चाहिए।

use v5.14;
# Make Perl recognize UTF-8 encoded characters in literal strings.
# For this to work: Make sure your text-editor is using UTF-8, so
# that bytes on disk are really UTF-8 encoded.
use utf8;

# Ensure that possible error messages printed to screen are converted to UTF-8.
# For this to work: Check that your terminal emulator is using UTF-8.
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
    
my $filename = 'æ€'; # $filename is now an internally UTF-8 encoded string. 

# Note: in the following it is assumed that $filename has the internal UTF-8
#  flag set, if $filename is pure ASCII, it will also work since its encoding
#  overlaps with UTF-8. However, if it has another encoding like extended ASCII,
#  $filename will be written with that encoding and not UTF-8. 
# Note: it is not necessary to encode $filename as UTF-8 here
#  since Perl is using UTF-8 as its internal encoding of $filename already

# Example1  -- using open()
open ( my $fh, '>', $filename ) or die "Could not open '$filename': $!";
close $fh;

# Example2 -- using qx() and touch
qx{touch $filename};

# Example3 -- using system() and touch
system 'touch', $filename;

# Example4 -- using File::Touch
use File::Touch;
eval { touch( $filename ) }; die "Could not create file '$filename': $!" if $@;

फ़ाइल नाम पढ़ें

पर्ल बिलिन फ़ंक्शंस या मॉड्यूल द्वारा लौटाए गए फ़ाइलनाम को डिकोड करने का प्रयास नहीं करता है। पर्लेन का प्रतिनिधित्व करने वाले ऐसे तारों को हमेशा स्पष्ट रूप से डिकोड किया जाना चाहिए, ताकि पर्ल के लिए उन्हें यूनिकोड के रूप में पहचाना जा सके।

use v5.14;
use Encode qw(decode_utf8);

# Ensure that possible error messages printed to screen are converted to UTF-8.
# For this to work: Check that you terminal emulator is using UTF-8.
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

# Example1  -- using readdir()
my $dir = '.';
opendir(my $dh, $dir) or die "Could not open directory '$dir': $!";
while (my $filename = decode_utf8(readdir $dh)) {
    # Do something with $filename
}
close $dh;

# Example2  -- using getcwd()
use Cwd qw(getcwd);
my $dir = decode_utf8( getcwd() );

# Example3  -- using abs2rel()
use File::Spec;
use utf8;
my $base = 'ø';
my $path = "$base/b/æ";
my $relpath = decode_utf8( File::Spec->abs2rel( $path, $base ) );
# Note: If you omit $base, you need to encode $path first:
use Encode qw(encode_utf8);
my $relpath = decode_utf8( File::Spec->abs2rel( encode_utf8( $path ) ) );

# Example4  -- using File::Find::Rule (part1 matching a filename)
use File::Find::Rule;
use utf8;
use Encode qw(encode_utf8);
my $filename = 'æ';
# File::Find::Rule needs $filename to be encoded
my @files = File::Find::Rule->new->name( encode_utf8($filename) )->in('.');
$_ = decode_utf8( $_ ) for @files;

# Example5  -- using File::Find::Rule (part2 matching a regular expression)
use File::Find::Rule;
use utf8;
my $pat = '[æ].$'; # Unicode pattern
# Note: In this case:  File::Find::Rule->new->name( qr/$pat/ )->in('.')
#  will not work since $pat is Unicode and filenames are bytes
#  Also encoding $pat first will not work correctly
my @files;
File::Find::Rule->new->exec( sub { wanted( $pat, \@files ) } )->in('.');
$_ = decode_utf8( $_ ) for @files;
sub wanted {
    my ( $pat, $files ) = @_;
    my $name = decode_utf8( $_ );
    my $full_name = decode_utf8( $File::Find::name );
    push @$files, $full_name if $name =~ /$pat/;
}

नोट: यदि आप फ़ाइल नाम में अमान्य UTF-8 के बारे में चिंतित हैं, तो उपरोक्त उदाहरणों में decode_utf8( ... ) के उपयोग को संभवतः decode( 'utf-8', ... ) बदला जाना चाहिए। ऐसा इसलिए है क्योंकि decode_utf8( ... ) decode( 'utf8', ... ) decode_utf8( ... ) का एक पर्याय है और एनकोडिंग utf-8 और utf8 बीच अंतर है (अधिक जानकारी के लिए नीचे देखें टिप्पणियां ) जहां utf-8 अधिक है utf8 तुलना में स्वीकार्य क्या है पर सख्त।

एक-लाइनर्स के लिए कमांड लाइन स्विच

Utf8 pragma सक्षम करें

एक-लाइनर में utf8 pragma को सक्षम करने के लिए, पर्ल इंटरप्रेटर को -Mutf8 विकल्प के साथ बुलाया जाना चाहिए:

perl -Mutf8 -E 'my $人 = "human"; say $人'

-C स्विच के साथ यूनिकोड हैंडलिंग

-C कमांड लाइन ध्वज आपको यूनिकोड सुविधाओं को नियंत्रित करने देता है। इसके बाद विकल्प पत्रों की सूची दी जा सकती है।

मानक I / O

  • I - STDIN UTF-8 में होगा
  • O - STDOUT UTF-8 में होगा
  • E - STDERR UTF-8 में होगा
  • IOE लिए S - शॉर्टहैंड, मानक I / O स्ट्रीम UTF-8 में होंगे
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'

लिपि के तर्क

  • A - @ARGV को UTF-8 एन्कोडेड स्ट्रिंग्स की एक सरणी के रूप में मानता है
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед

डिफ़ॉल्ट पर्ल परत

  • i - इनपुट स्ट्रीम के लिए UTF-8 डिफ़ॉल्ट PerlIO लेयर है
  • o - UTF-8 आउटपुट स्ट्रीम के लिए डिफ़ॉल्ट पर्ल परत है
  • D - io लिए आशुलिपि
perl -CD -Mutf8 -e 'open my $fh, ">", "utf8.txt" or die $!; print $fh "개미 조심해"'

-M और -C स्विच संयुक्त हो सकते हैं:

perl -CASD -Mutf8 -E 'say "Ματαιότης ματαιοτήτων\n"';

मानक I / O

मानक I / O फ़ाइलहैंडल ( STDIN , STDOUT , और STDERR ) के लिए उपयोग की जाने वाली binmode का उपयोग करके प्रत्येक हैंडल के लिए अलग से सेट की जा सकती है:

binmode STDIN, ':encoding(utf-8)';
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

नोट: जब कोई सामान्य रूप से पढ़ना पसंद करेगा :encoding(utf-8) ओवर :utf8 , अधिक जानकारी के लिए रिमार्क्स देखें।

वैकल्पिक रूप से, आप open प्रागमा का उपयोग कर सकते हैं।

# Setup such that all subsequently opened input streams will use ':encoding(utf-8)'
# and all subsequently opened output streams will use ':utf8'
# by default
use open (IN => ':encoding(utf-8)', OUT => ':utf8');
# Make the (already opened) standard file handles inherit the setting 
# given by the IO settings for the open pragma
use open ( :std );
# Now, STDIN has been converted to ':encoding(utf-8)', and 
# STDOUT and STDERR have ':utf8'

वैकल्पिक रूप से, सभी फ़ाइलहैंडल सेट करने के लिए (दोनों जिन्हें अभी भी खोला जाना है और मानक वाले भी) उपयोग करने के लिए :encoding(utf-8) :

use open qw( :encoding(utf-8) :std );

फ़ाइल संभालती है

खुले के साथ एन्कोडिंग सेट करना ()

पाठ फ़ाइल खोलते समय, आप इसे स्पष्ट रूप से तीन-तर्क open() साथ एन्कोडिंग निर्दिष्ट कर सकते हैं। इस एन-डिकोडर को फाइल हैंडल से जोड़ा जाता है जिसे "I / O लेयर" कहा जाता है:

my $filename = '/path/to/file';
open my $fh, '<:encoding(utf-8)', $filename or die "Failed to open $filename: $!";

के बीच मतभेदों की चर्चा के लिए रिमार्क्स देखें :utf8 और :encoding(utf-8)

Binmode () के साथ एन्कोडिंग सेट करना

वैकल्पिक रूप से, आप अलग-अलग फ़ाइल हैंडल के लिए एन्कोडिंग सेट करने के लिए बिनमोड () का उपयोग कर सकते हैं:

my $filename = '/path/to/file';
open my $fh, '<', $filename or die "Failed to open $filename: $!";
binmode $fh, ':encoding(utf-8)';

खुला प्रज्ञा

प्रत्येक फ़ाइल हैंडल के लिए अलग से एन्कोडिंग स्थापित करने से बचने के लिए, आप open प्रागमा का उपयोग डिफॉल्ट I / O लेयर को बाद के सभी कॉल्स द्वारा open() फंक्शन और इसी तरह के ऑपरेटर्स को इस प्रैग्मा के लेक्सिकल दायरे में सेट करने के लिए कर सकते हैं:

# Set input streams to ':encoding(utf-8)' and output streams to ':utf8'
use open (IN => ':encoding(utf-8)', OUT => ':utf8');
# Or to set all input and output streams to ':encoding(utf-8)'
use open ':encoding(utf-8)';

कमांड लाइन -C फ्लैग के साथ एन्कोडिंग सेट करना

अंत में, पेर-इंटरप्रेटर को एक -CD फ्लैग के साथ चलाना संभव है जो UTF-8 को डिफ़ॉल्ट I / O लेयर के रूप में लागू करता है। हालाँकि, इस विकल्प को टाला जाना चाहिए क्योंकि यह विशिष्ट उपयोगकर्ता व्यवहार पर निर्भर करता है जिसे भविष्यवाणी नहीं की जा सकती है और न ही नियंत्रित किया जा सकता है।

Utf8 pragma: अपने स्रोतों में यूनिकोड का उपयोग करना

utf8 pragma इंगित करता है कि स्रोत कोड को UTF-8 के रूप में व्याख्या किया जाएगा। निश्चित रूप से, यह केवल तभी काम करेगा जब आपका टेक्स्ट एडिटर भी सोर्स को UTF-8 के रूप में सहेज रहा हो।

अब, स्ट्रिंग शाब्दिकों में मनमाने ढंग से यूनिकोड वर्ण हो सकते हैं; पहचानकर्ता में यूनिकोड भी हो सकता है लेकिन केवल शब्द-जैसे अक्षर (अधिक जानकारी के लिए perldata और perlrecharclass देखें):

use utf8;
my $var1 = '§я§©😄';      # works fine
my $я = 4;                # works since я is a word (matches \w) character
my $p§2 = 3;              # does not work since § is not a word character.
say "ya" if $var1 =~ /я§/; # works fine (prints "ya")

नोट : टर्मिनल पर टेक्स्ट प्रिंट करते समय, सुनिश्चित करें कि यह UTF-8 का समर्थन करता है। *

आउटपुट और स्रोत एन्कोडिंग के बीच जटिल और काउंटर-सहज संबंध हो सकते हैं। UTF-8 टर्मिनल पर चलने पर, आप पा सकते हैं कि utf8 प्रगामा को जोड़ने से चीजें टूटने लगती हैं:

$ perl -e 'print "Møøse\n"'
Møøse
$ perl -Mutf8 -e 'print "Møøse\n"'
M��se
$ perl -Mutf8 -CO -e 'print "Møøse\n"'
Møøse

पहले मामले में, पर्ल स्ट्रिंग को कच्ची बाइट्स के रूप में मानता है और उन्हें इस तरह प्रिंट करता है। जैसा कि ये बाइट्स UTF-8 के रूप में मान्य होते हैं, वे सही दिखते हैं भले ही पर्ल को वास्तव में पता नहीं है कि वे कौन से वर्ण हैं (उदाहरण के लिए length("Møøse") 7, 5 नहीं, बल्कि 5) वापस आएंगे। एक बार जब आप -Mutf8 जोड़ -Mutf8 , तो पर्ल सही ढंग से UTF-8 स्रोत को वर्णों में सही रूप से डिकोड करता है, लेकिन आउटपुट लैटिन -1 मोड में डिफ़ॉल्ट रूप से होता है और लैटिन -1 को UTF-8 टर्मिनल में प्रिंट करने से काम नहीं चलता है। केवल तभी जब आप STDOUT को UTF-8 का उपयोग करके स्विच करते हैं -CO आउटपुट को सही करेगा।

use utf8 मानक I / O एन्कोडिंग को प्रभावित नहीं करता है और न ही फ़ाइल हैंडल को!

अमान्य UTF-8 को संभालना

अवैध UTF-8 पढ़ना

UTF-8 एन्कोडेड डेटा को पढ़ते समय, इस तथ्य से अवगत होना महत्वपूर्ण है कि UTF-8 एन्कोडेड डेटा अमान्य या विकृत हो सकता है। इस तरह के डेटा को आमतौर पर आपके कार्यक्रम द्वारा स्वीकार नहीं किया जाना चाहिए (जब तक कि आपको पता नहीं है कि आप क्या कर रहे हैं)। जब अप्रत्याशित रूप से विकृत डेटा का सामना करना पड़ता है, तो विभिन्न कार्यों पर विचार किया जा सकता है:

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

डिफ़ॉल्ट रूप से, पर्ल आपको एन्कोडिंग ग्लिट्स के बारे में warn देगा, लेकिन यह आपके प्रोग्राम को रद्द नहीं करेगा। आप UTF-8 चेतावनियों को घातक बनाकर अपने कार्यक्रम को निरस्त कर सकते हैं, लेकिन घातक चेतावनियों में चेतावनी के बारे में जागरूक रहें

निम्न उदाहरण डिस्क को आईएसओ 8859-1 में 3 बाइट्स लिखता है। इसके बाद यूटीएफ -8 एनकोडेड डेटा के रूप में बाइट्स को फिर से पढ़ने की कोशिश करता है। बाइट्स में से एक, 0xE5 , एक अमान्य UTF-8 एक बाइट अनुक्रम है:

use strict;
use warnings;
use warnings FATAL => 'utf8';

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
my $bytes = "\x{61}\x{E5}\x{61}";  # 3 bytes in iso 8859-1: aåa
my $fn = 'test.txt';
open ( my $fh, '>:raw', $fn ) or die "Could not open file '$fn': $!";
print $fh $bytes;
close $fh;
open ( $fh, "<:encoding(utf-8)", $fn ) or die "Could not open file '$fn': $!";
my $str = do { local $/; <$fh> };
close $fh;
print "Read string: '$str'\n";

घातक चेतावनी के साथ कार्यक्रम समाप्त होगा:

utf8 "\xE5" does not map to Unicode at ./test.pl line 10.

लाइन 10 यहाँ दूसरी अंतिम पंक्ति है, और फ़ाइल से एक लाइन पढ़ने की कोशिश करते समय त्रुटि <$fh> साथ लाइन के हिस्से में होती है।

यदि आप उपरोक्त कार्यक्रम में चेतावनी घातक नहीं बनाते हैं, तो पर्ल अभी भी चेतावनी को प्रिंट करेगा। हालाँकि, इस स्थिति में यह चार अक्षरों \xE5 को धारा में डालकर विकृत बाइट 0xE5 से पुनर्प्राप्त करने का प्रयास करेगा, और फिर अगले बाइट के साथ जारी रहेगा। परिणामस्वरूप, कार्यक्रम प्रिंट होगा:

Read string: 'a\xE5a'


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow