수색…


비고

파일 이름 인코딩에 대한 경고


Filename Encoding은 특정 플랫폼 뿐만 아니라 파일 시스템과 도 관련이 있음을 언급 할 가치가 있습니다.

주어진 파일 이름을 인코딩하고 쓸 수 있기 때문에, 나중에 같은 파일 이름을 읽기 위해 열려고해도 똑같은 이름이 붙을 것이라고 가정하는 것은 전적으로 안전합니다 (그러나 대개 그렇습니다).

예를 들어, 유니 코드를 지원하지 않는 FAT16 과 같은 파일 시스템에 쓰면 파일 이름이 자동으로 ASCII 호환 형식으로 변환 될 수 있습니다.

그러나 명시 적 이름 지정으로 작성하고 읽고 쓸 수있는 파일이 다른 호출을 통해 쿼리 될 때 동일한 호출을 받았다고 가정하는 것이 훨씬 안전하지 않습니다. 예를 들어 readdir 은 지정한 파일 이름과 다른 바이트를 반환 할 수 open .

VAX와 같은 일부 시스템에서는 파일 확장자 가 OS에 의해 변경 될 수 있기 때문에 readdirfoo.bar 처럼 파일 이름에 대해 open 과 함께 지정한 동일한 파일 이름을 반환한다고 항상 가정 할 수도 없습니다.

또한 UNIX에는 /\0 만 제외하고 OS에서 허용하는 파일 이름에 대해 매우 자유로운 일련의 합법적 인 문자 집합이 있습니다. Windows에서는 파일 이름에서 금지 된 특정 문자 범위가 있으며 오류가 발생할 수 있습니다.

여기에 많은주의를 기울이고, 선택이 있다면 파일 이름으로 멋진 트릭을 피하고 사용하는 멋진 트릭이 일관성 있는지 확인하기위한 테스트를 항상 거쳐야합니다.

CPAN 용 코드를 작성하는 경우와 같이 제어 할 수없는 플랫폼에서 실행되도록 의도 된 코드를 작성하는 경우 두 배의주의를 기울여야 하며 사용자 기반의 최소 5 %가 선택에 의해, 우연히 또는 통제를 벗어난 권한으로 고대 또는 부러진 기술을 사용하고, 이들이 버그를 만들기 위해 공모 할 것입니다.

: 인코딩 (utf8) vs : utf8


UTF-8은 Perl에서 문자열을 표현하기위한 내부 형식 중 하나이기 때문에 인코딩 / 디코딩 단계를 건너 뛸 수 있습니다. 대신 :encoding(utf-8) 대신 데이터가 이미 UTF-8 인 경우 :utf8 사용할 수 있습니다. :utf8 은 출력 스트림과 함께 안전하게 사용할 수 있지만 입력 스트림의 경우 잘못된 바이트 시퀀스가있을 때 내부 불일치가 발생하므로 위험 할 수 있습니다. 또한, :utf8 을 입력으로 사용하면 보안 위반이 발생할 수 있으므로 :encoding(utf-8) 을 사용하는 것이 좋습니다.

추가 정보 : 인코딩과 utf8의 차이점은 무엇입니까?

UTF-8 대 UTF8 대 UTF8


Perl v5.8.7 부터 "UTF-8" (대시 포함)은 엄격하고 보안을 고려한 형태로 UTF-8을 의미하는 반면 "utf8" 은 자유롭고 자유로운 형식의 UTF-8을 의미합니다.

예를 들어 "utf8"0xFFFFFFFF 와 같이 유니 코드에없는 코드 포인트에 사용할 수 있습니다. 그에 상응하여 "\x{FE}\x{83}\x{BF}\x{BF}\x{BF}\x{BF}\x{BF}" 와 같은 잘못된 UTF-8 바이트 시퀀스가 "UTF-8" 인코딩은 유효한 유니 코드 범위를 벗어난 코드 포인트로 디코딩 할 수 없으며 대신 대체 문자 ( 0xFFFD )를 제공하지만 "utf8" 사용할 때는 잘못된 유니 코드 (유효한 Perl) 코드 포인트 ( 0xFFFFFFFF )가 사용됩니다.

인코딩 이름은 대소 문자를 구분하지 않으므로 "UTF8""utf8" 과 동일합니다 (즉 , 엄격하지 않은 변형).

세부 정보 : UTF-8 vs. utf8 vs. UTF8

더 많은 독서


Perl의 유니 코드 처리에 대한 자세한 내용은 다음 소스에서 자세히 설명합니다.

stackoverflow.com의 게시물 (주의 : 최신이 아닐 수도 있음) :

유튜브 동영상 :

파일 이름 만들기

다음 예제는 UTF-8 인코딩을 사용하여 디스크의 파일 이름 (및 디렉토리 이름)을 나타냅니다. 다른 인코딩을 사용하려면 Encode::encode(...) 사용해야 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 $@;

파일 이름 읽기

Perl은 기본 함수 나 모듈에 의해 반환 된 파일 이름을 디코딩하지 않습니다. 파일명을 나타내는 문자열은 Perl이 유니 코드로 인식 할 수 있도록 항상 명시 적으로 해독되어야합니다.

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', ... ) 및 인코딩 된 차이가 utf-8utf8 (참조 소견 자세한 내용은 아래)를 여기서 utf-8utf8 보다 수용 할 수있는 것에 엄격한

한 줄짜리 명령 줄 스위치

utf8 pragma 사용

one-liner에서 utf8 pragma를 사용하려면 perl 인터프리터를 -Mutf8 옵션과 함께 호출해야합니다.

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

-C 스위치를 사용한 유니 코드 처리

-C 명령 행 플래그를 사용하여 유니 코드 기능을 제어 할 수 있습니다. 그 뒤에 옵션 문자 목록을 올릴 수 있습니다.

표준 I / O

  • I - STDINUTF-8 이 될 것입니다.
  • O - STDOUTUTF-8 형식입니다.
  • E - STDERRUTF-8 이 될 것입니다.
  • S - IOE 약자로, 표준 I / O 스트림은 UTF-8
echo "Ματαιότης ματαιοτήτων" | perl -CS -Mutf8 -nE 'say "ok" if /Ματαιότης/'

스크립트의 주장

  • A - @ARGVUTF-8 인코딩 된 문자열의 배열로 처리합니다.
perl -CA -Mutf8 -E 'my $arg = shift; say "anteater" if $arg eq "муравьед"' муравьед

기본 PerlIO 계층

  • i - UTF-8 은 입력 스트림의 기본 PerlIO 레이어입니다.
  • o - UTF-8 은 출력 스트림을위한 기본 PerlIO 레이어입니다.
  • 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 , STDOUTSTDERR )에 사용할 인코딩은 binmode 사용하여 핸들마다 별도로 설정할 수 있습니다.

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

참고 : 일반적으로 읽는 사람은 :encoding(utf-8) :utf8 선호합니다 :encoding(utf-8) 자세한 내용은 비고 참조).

또는 open pragma를 사용할 수 있습니다.

# 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) 을 사용하십시오 :encoding(utf-8) :

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

파일 핸들

open ()로 인코딩 설정하기

텍스트 파일을 열 때 3 개의 인자로 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 ()로 인코딩 설정하기

또는 binmode ()를 사용하여 개별 파일 핸들의 인코딩을 설정할 수 있습니다.

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

오픈 프라그 마

별도로 각 파일 핸들의 인코딩을 설정하지 않으 open pragma를 사용하여이 pragma의 어휘 범위 내에서 open() 함수 및 유사한 연산자에 대한 이후의 모든 호출에서 사용되는 기본 I / O 레이어를 설정할 수 있습니다.

# 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 플래그

마지막으로 UTF-8을 기본 I / O 레이어로 적용하는 -CD 플래그를 사용하여 perl 인터프리터를 실행할 수도 있습니다. 그러나이 옵션은 예측하거나 제어 할 수없는 특정 사용자 동작에 의존하기 때문에 피해야합니다.

utf8 pragma : 소스에서 유니 코드 사용

utf8 pragma는 소스 코드가 UTF-8로 해석됨을 나타냅니다. 물론 이것은 텍스트 편집기가 UTF-8로 소스를 저장하는 경우에만 작동합니다.

자, 문자열 리터럴은 임의의 유니 코드 문자를 포함 할 수 있습니다. 식별자는 유니 코드를 포함 할 수 있지만 단어와 유사한 문자 만 포함 할 수 있습니다 (자세한 내용은 perldataperlrecharclass 참조).

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 터미널에서 실행 utf8utf8 pragma를 추가하면 문제가 발생할 수 있습니다.

$ 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

첫 번째 경우에 Perl은 문자열을 원시 바이트로 처리하여이를 인쇄합니다. 이 바이트들은 유효한 UTF-8 일 때 Perl이 실제로 어떤 문자인지를 알지 못하더라도 (예 : length("Møøse") 는 5가 아닌 7을 반환합니다 length("Møøse") . 일단 -Mutf8 을 추가하면 Perl은 UTF-8 소스를 문자로 올바르게 디코딩하지만, 출력은 기본적으로 Latin-1 모드이며 Latin-1을 UTF-8 터미널에 인쇄하는 것은 작동하지 않습니다. -CO 를 사용하여 STDOUT 을 UTF-8로 전환 할 때만 출력이 정확합니다.

use utf8 표준 I / O 인코딩이나 파일 핸들에 영향을 미치지 않습니다!

잘못된 UTF-8 처리

잘못된 UTF-8 읽기

UTF-8로 인코딩 된 데이터를 읽을 때 UTF-8로 인코딩 된 데이터가 유효하지 않거나 형식이 잘못 될 수 있다는 사실을 알고 있어야합니다. 그러한 데이터는 일반적으로 프로그램에 의해 받아 들여지지 않아야합니다 (자신이하는 일을 알지 못한다면). 예기치 않게 잘못된 형식의 데이터가 발생하면 다른 동작을 고려할 수 있습니다.

  • 스택 추적 또는 오류 메시지를 인쇄하고 정상적으로 프로그램을 중단하거나
  • 잘못된 바이트 시퀀스가 ​​나타난 위치에 대체 문자를 삽입하고 STDERR에 경고 메시지를 인쇄하고 아무 일도 일어나지 않을 때 계속해서 읽습니다.

기본적으로 Perl은 글리치 인코딩에 대해 warn 하지만 프로그램을 중단하지는 않습니다. UTF-8 경고를 치명적으로 만들어 프로그램을 중단시킬 수 있지만 치명적인 경고 의주의 사항을 알고 있어야합니다.

다음 예제는 ISO 8859-1 인코딩의 3 바이트를 디스크에 씁니다. 그런 다음 다시 바이트를 UTF-8로 인코딩 된 데이터로 다시 읽으려고합니다. 바이트 중 하나 인 0xE5 는 유효하지 않은 UTF-8 1 바이트 시퀀스입니다.

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> 파일에서 한 줄을 읽으 려 할 때 <$fh> 가있는 줄 부분에서 오류가 발생합니다.

위의 프로그램에서 경고를 치명적으로 만들지 않으면 Perl은 여전히 ​​경고를 출력합니다. 그러나이 경우 스트림에 4 개의 문자 \xE5 를 삽입하여 조작 된 바이트 0xE5 를 복구하려고 시도하고 다음 바이트로 계속 진행합니다. 결과적으로 프로그램은 다음을 인쇄합니다.

Read string: 'a\xE5a'


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow