2016-09-09 4 views
1
use open qw(:encoding(UTF-8) :std); 

위의 문장은 어휘 범위에서만 유효하며 범위 외부에는 영향을 미치지 않아야합니다. 그러나 나는 다음을 관찰했다.Perl의 "open open ..."에 대한 어휘 범위 지정의 이해

$ cat data 
€ 
# 1
$ perl -e ' 
    open (my $fh, "<encoding(UTF-8)", "data"); 
    print($_) while <$fh>;' 
Wide character in print at -e line 1, <$fh> line 1. 
€ 

Wide character ... 경고가 여기에 최적입니다. 그러나

# 2
$ perl 
    my ($fh, $row); 
    { 
     use open qw(:encoding(UTF-8) :std); 
     open ($fh, "<", "data"); 
    } 
    $row = <$fh>; 
    chomp($row); 
    printf("%s (0x%X)", $row, ord($row)); 

    € (0x20AC) 

는 와이드 문자 경고를 표시하지 않습니다! 여기에 무슨 일이 일어나고 있습니까?

  • 오픈 프라그마를 사용하여 STDOUT을 포함하여 IO 스트림을 UTF-8로 설정하고 있습니다.
  • 동일한 범위 내에서 파일 열기. 문자를 멀티 바이트 문자로 읽습니다.
  • 범위 밖에서 인쇄 중입니다. print 문에는 "와이드 문자"경고가 표시되어야하지만 그렇지 않습니다. 왜?

지금 다음, 약간의 변화를 보면

my ($fh, $row); 
{ 
    use open qw(:encoding(UTF-8) :std); 
} 
open ($fh, "<", "data"); 
$row = <$fh>; 
chomp($row); 
printf("%s (0x%X)", $row, ord($row)); 

⬠(0xE2) 

지금 열린 문은 어휘 범위를 벗어나 있기 때문에이 시간의 open 비 UTF-8로 파일을 연 # 방법.

use open qw(:encoding(UTF-8) :std); 문은 어휘 범위 내에서 STDOUT을 전체적으로 변경하지만 STDIN을 변경합니까?

+0

YAPC NA 2016에서 Ricardo Signes의 토크 [백만 억 달러짜리 캐릭터] (https://www.youtube.com/watch?v=TmTeXcEixEg)를 참조하십시오. 'open'pragma에 대한 논의는 [35 : 44] (https://youtu.be/TmTeXcEixEg?t=2144) –

+0

예 'open q w (: std)'는 표준 핸들을 전역 적으로 변경합니다. 위에서 언급 한 리카르도 (Ricardo)의 말처럼. –

+0

': std' 부분은 어휘 적으로 범위가 지정되지 않고 단편에서 사용하지 않는'open()'에서 사용되는 기본 레이어 만 변경됩니다. – ikegami

답변

3

STDIN을 사용하고 있지 않습니다. 명시 적 인코딩 (마지막 예제 제외)을 사용하여 파일을 열고 읽는 중입니다.

use open qw(:std ...)표준 파일 핸들에 영향을 미치지 만 표준 출력 만 사용합니다. 표준 출력에 UTF-8 데이터를 사용하지 않으면 경고 메시지가 나타납니다.

마지막 예제에서는 명시 적 인코딩으로 데이터를 읽지 않으므로 표준 출력으로 인쇄하면 이미 손상된 것입니다.

그것이 무엇이든 상관없이 인코딩의 트릭입니다. 프로세스의 모든 부분이 정확해야합니다.

use open을 모든 파일 핸들에 적용하려면 파일을 다르게 가져와야합니다. 문서 맨 위에 몇 가지 예가 있습니다.

+0

당신 말이 맞아요. STDIN을 사용하지 않았습니다. 그러나 나는 아직도 # 2에서 경고하지 않는 이유를 분명하지 않습니다. '$ row'는 하나의 멀티 바이트 문자를 포함해야합니다. 그러나 STDOUT에는 UTF-8 플래그가 사용 가능하지 않습니다. 그러므로'print'는 "와이드 문자 ..."경고를 보여 주어야합니다. 여기에 실종 된 부분이 있습니까? – Samiron

+0

@Samiron 어쩌면 : 오픈의 표준 부분은 어휘 적으로 범위가 지정되지 않았습니까? – ysth

1

불행하게도, open qw(:std) pragma는 그것이 IO의 표준과 관련된 층 세계적으로 STDIN, STDOUTSTDERR 처리를 변경 이후 어휘 프라그처럼 행동하지 않는 것. use 문이 컴파일 타임에 발생하기 때문에 원본 파일의 이전 코드도 영향을받습니다.그래서 (내 리눅스 플랫폼) 다음

say join ":", PerlIO::get_layers(\*STDIN); 
{ 
    use open qw(:encoding(UTF-8) :std); 
} 

지문 :

unix:perlio:encoding(utf-8-strict):utf8 

use open qw(:encoding(UTF-8) :std)없이 그냥 unix:perlio를 인쇄 할 것입니다 반면. 출력

use feature qw(say); 
use strict; 
use warnings; 
use utf8; 

my $str = "€"; 
say join ":", PerlIO::get_layers(\*STDOUT); 
{ 
    open (my $out, '>&STDOUT') or die "Could not duplicate stdout: $!"; 
    binmode $out, ':encoding(UTF-8)'; 
    say $out $str; 
} 
say join ":", PerlIO::get_layers(\*STDOUT); 
say $str; 

:

unix:perlio 
€ 
unix:perlio 
Wide character in say at ./p.pl line 16. 
€ 

예를 들어 글로벌 STDOUT에 영향을주지 할 수있는 방법은 어휘 범위 내에서 핸들을 복제하고 그 범위 내에서 중복 핸들 IO 레이어를 추가하는 것입니다