왜 현대 Perl은 기본적으로 UTF-8을 피합니까?


Answers

유니 코드 텍스트를 처리하는 데는 두 단계가 있습니다. 첫 번째는 "어떻게 정보를 입력하고 출력해도 정보를 잃지 않고 출력 할 수 있습니다"입니다. 두 번째는 "현지 언어 규칙에 따라 텍스트를 처리하는 방법"입니다.

tchrist의 게시물은 둘 다 다루지 만, 두 번째 부분은 그의 게시물에있는 텍스트의 99 %가 나오는 곳입니다. 대부분의 프로그램은 I / O를 올바르게 처리하지 않기 때문에 정규화 및 데이터 정렬에 대해 걱정하기 시작하기 전에이를 이해하는 것이 중요합니다.

이 게시물은 첫 번째 문제를 해결하는 것을 목표로합니다.

Perl로 데이터를 읽을 때 인코딩이 무엇인지 신경 쓰지 않습니다. 그것은 약간의 메모리를 할당하고 그곳에서 바이트를 숨 깁니다. print $str 을 쓰면 터미널에 그 바이트가 블럭됩니다.이 바이트는 UTF-8로 기록 된 모든 내용을 가정하고 텍스트가 표시된다고 가정합니다.

기이.

제외하고는 그렇지 않습니다. 데이터를 텍스트로 취급하려고하면 Something Bad가 발생하는 것을 볼 수 있습니다. Perl이 문자열에 대해 생각하는 것과 문자열에 대해 생각하는 것이 일치하지 않는지 확인하려면 length 보다 length 합니다. 다음과 같이 한 줄짜리를 작성하십시오. perl -E 'while(<>){ chomp; say length }' perl -E 'while(<>){ chomp; say length }' 입력하고 文字化け 하면 12를 얻습니다. 정답이 아닙니다, 4.

Perl은 문자열이 텍스트가 아니라고 가정하기 때문입니다. 당신에게 옳은 대답을주기 전에 그것은 텍스트라는 것을 말해야합니다.

그건 쉽지. Encode 모듈에는이를 수행하는 기능이 있습니다. 일반적인 진입 점은 Encode::decode (물론 use Encode qw(decode) ). 이 함수는 바깥 세상에서 문자열 ( "8 비트 바이트"라고 말하는 멋진 방법 인 "옥텟"이라고 부름)을 가져 와서 Perl이 이해할 수있는 텍스트로 변환합니다. 첫 번째 인수는 "UTF-8"또는 "ASCII"또는 "EUC-JP"와 같은 문자 인코딩 이름입니다. 두 번째 인수는 문자열입니다. 반환 값은 텍스트가 들어있는 Perl 스칼라입니다.

( Encode::decode_utf8 에는 UTF-8을 가정 한 Encode::decode_utf8 도 있습니다.)

한 라이너를 다시 작성하면

perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

우리는 문자化け를 입력하고 결과로 "4"를 얻습니다. 성공.

바로 거기에서 Perl의 유니 코드 문제의 99 %에 대한 해결책입니다.

핵심은 모든 텍스트가 프로그램에 올 때마다 반드시 해독해야한다는 것입니다. 인터넷에서 문자를 전송할 수 없습니다. 파일에는 문자를 저장할 수 없습니다. 데이터베이스에 문자가 없습니다. 옥텟 만 있고, Perl에서는 옥텟을 문자로 취급 할 수 없습니다. Encode 모듈을 사용하여 인코딩 된 8 진수를 Perl 문자로 디코딩해야합니다.

나머지 절반은 프로그램에서 데이터를 가져 오는 것입니다. 그렇게하기 쉽습니다. use Encode qw(encode) , 데이터 인코딩 (UTF-8을 이해하는 터미널, Windows의 파일에 대해 UTF-16 등)을 결정한 다음 encode($encoding, $data) 결과를 출력합니다. encode($encoding, $data) 를 출력한다.

이 작업은 프로그램이 작동하는 Perl의 문자를 외부 세계에서 사용할 수있는 옥텟으로 변환합니다. 인터넷이나 터미널을 통해 문자를 전송할 수 있다면 훨씬 쉽습니다. 그러나 옥텟 만 사용할 수는 없습니다. 따라서 문자를 옥텟으로 변환해야합니다. 그렇지 않으면 결과가 정의되지 않습니다.

요약하면 : 모든 출력을 인코딩하고 모든 입력을 디코딩합니다.

이제 우리는이 문제를 조금이라도 어렵게 만드는 세 가지 문제에 대해 이야기 할 것입니다. 첫 번째는 도서관입니다. 텍스트를 올바르게 처리합니까? 그 대답은 ... 시도합니다. 웹 페이지를 다운로드하면 LWP는 결과를 다시 텍스트로 제공합니다. 결과에 대해 올바른 메서드를 호출하면 content 가 아니라 contentdecoded_content 가 발생합니다. 서버에서 가져온 옥텟 스트림입니다. 데이터베이스 드라이버는 비정상적 일 수 있습니다. Perl과 함께 DBD :: SQLite를 사용하면 제대로 작동하지만 다른 도구가 UTF-8이 아닌 다른 인코딩으로 저장된 텍스트를 데이터베이스에 넣으면 ... 음 ... 제대로 처리되지 않습니다. 올바르게 처리 할 코드를 작성할 때까지

일반적으로 데이터를 출력하는 것이 더 쉽지만 "인쇄 와이드 문자"가 표시되면 인코딩 어딘가에 엉망이된다는 것을 알게됩니다. 그 경고는 "어이, 당신은 외부 세계에 펄 문자를 누출하려고 노력하고 있으며 그것은 아무 의미가 없다"는 것을 의미합니다. 프로그램이 작동하는 것처럼 보입니다. 왜냐하면 다른 쪽에서는 보통 원시 Perl 문자를 올바르게 처리하기 때문입니다. 그러나 매우 손상되어 언제든지 작동을 멈출 수 있습니다. 명시적인 Encode::encode 해결하십시오!

두 번째 문제는 UTF-8로 인코딩 된 소스 코드입니다. 각 파일의 맨 위에 use utf8use utf8 한다고하지 않는 한, Perl은 소스 코드가 UTF-8이라고 가정하지 않습니다. 즉, my $var = 'ほげ' 과 같은 말을 할 때마다 프로그램에 쓰레기를 주입하여 모든 것을 완전히 무섭게 만듭니다. "utf8 사용"할 필요는 없지만 그렇게하지 않으면 프로그램에서 비 ASCII 문자를 사용하면 안됩니다 .

세 번째 문제는 Perl이 과거를 처리하는 방법입니다. 오래 전에 유니 코드와 같은 것이 없었으며 펄은 모든 것이 라틴어 -1 텍스트 또는 바이너리라고 가정했습니다. 따라서 데이터가 프로그램에 들어오고 텍스트로 처리하기 시작하면 Perl은 각 옥텟을 Latin-1 문자로 취급합니다. 그래서 우리는 "문자 化け"의 길이를 물었을 때 12 점을 얻었습니다. Perl은 Latin-1 문자열 "æååã"(12 문자 중 일부는 비 인쇄 임)를 사용한다고 가정했습니다.

이것을 "암시 적 업그레이드"라고하며, 완벽하게 합당한 일이지만, 텍스트가 Latin-1이 아닌 경우 원하는 것이 아닙니다. 그렇기 때문에 입력을 명시 적으로 해독하는 것이 중요합니다.하지 않으면 Perl이 잘못 처리 할 수 ​​있습니다.

사람들은 데이터의 절반이 적절한 문자열이고 문제는 여전히 바이너리입니다. Perl은 Latin-1 텍스트 인 것처럼 여전히 바이너리 인 부분을 해석 한 다음 올바른 문자 데이터와 결합합니다. 이렇게하면 캐릭터를 올바르게 처리하는 것처럼 보이게 할 수 있지만 실제로는 충분히 고칠 수 없습니다.

여기에 예가 있습니다 : UTF-8로 인코딩 된 텍스트 파일을 읽는 프로그램이 있습니다. 각 줄마다 유니 코드 PILE OF POOPILE OF POO 십시오. 당신은 그것을 다음과 같이 씁니다 :

while(<>){
    chomp;
    say "$_ 💩";
}

그런 다음 UTF-8로 인코딩 된 일부 데이터를 실행하십시오.

perl poo.pl input-data.txt

각 행의 끝에 poo가있는 UTF-8 데이터를 인쇄합니다. 완벽한 프로그램이 작동합니다!

하지만 아니, 이진 연결 만하는 것입니다. 파일에서 옥텟을 읽고, chomp로 \n 을 제거한 다음, PILE OF POO 문자의 UTF-8 표현으로 바이트를 PILE OF POO 있습니다. 파일에서 데이터를 디코딩하고 출력을 인코딩하도록 프로그램을 수정하면 똥 대신 쓰레기 ( "ð ©")가 표시됩니다. 이렇게하면 입력 파일을 디코딩하는 것이 잘못된 것이라고 믿게 될 것입니다. 그렇지 않습니다.

문제는 똥이 latin-1로 암묵적으로 업그레이드된다는 것입니다. use utf8 을 사용하여 바이너리 대신 리터럴 텍스트를 만들면 다시 작동합니다!

유니 코드를 사용하는 사람들을 도와 줄 때 가장 큰 문제는 바로 그 부분이었고 프로그램이 파손되었습니다. 정의되지 않은 결과에 대해서는 슬픈 일입니다. 오랫동안 작업 프로그램을 사용할 수는 있지만 수리를 시작할 때, 프로그램에 인 코드 / 디코드 문을 추가하고 중단하는 경우 더 많은 작업이 필요하다는 것을 의미하므로 걱정하지 마십시오. 다음부터 유니 코드를 처음부터 염두에두고 디자인하면 다음과 같은 작업이 수행됩니다. 훨씬 쉽게!)

Perl과 Unicode에 관해 알아야 할 모든 것입니다. Perl에게 데이터가 무엇인지 알려주면 모든 인기있는 프로그래밍 언어 중에서 유니 코드를 가장 잘 지원합니다. 그래도 텍스트가 어떤 종류의 텍스트인지 알게된다면, 데이터를 돌이킬 수 없게 버릴 것입니다. 오늘 UTF-8 단말기에서 프로그램이 작동한다고해서 내일 UTF-16 인코딩 된 파일로 작동한다는 것을 의미하지는 않습니다. 이제 안전하게 만들어 보시고 사용자의 데이터를 파괴하는 두통을 피하십시오!

유니 코드를 처리하는 쉬운 부분은 출력을 인코딩하고 입력을 디코딩하는 것입니다. 어려운 부분은 모든 입력과 출력을 찾고 어떤 인코딩인지 판단하는 것입니다. 그러나 그것이 당신이 큰돈을받는 이유입니다 :)

Question

Perl을 사용하여 빌드 된 최신 솔루션이 기본적으로 UTF-8 을 활성화하지 않는 이유가 궁금합니다.

핵심 Perl 스크립트에는 여러 가지 문제가 있다는 것을 이해합니다. 그러나 내 관점에서 볼 때, 21 세기에 커다란 새로운 프로젝트 (또는 큰 관점을 가진 프로젝트)는 처음부터 소프트웨어 UTF-8을 만들어야합니다. 아직도 나는 그것이 일어나는 것을 보지 못한다. 예를 들어 MooseUnicode 아닌 엄격한 경고를 허용합니다. Modern::Perl 은 상용구를 줄이지 만 UTF-8 처리는하지 않습니다.

왜? 2011 년 현대 Perl 프로젝트에서 UTF-8을 피할 이유가 있습니까?

@tchrist에 댓글을다는 것은 너무 길어서 여기에 추가 할 것입니다.

나는 나 자신을 분명히하지 않았다. 몇 가지를 추가하겠습니다.

tchrist 와 나는 비슷한 상황을 본다. 그러나 우리의 결론은 완전히 반대편에있다. 동의합니다. 유니 코드의 상황은 복잡합니다. 그러나 이것이 우리 (Perl 사용자와 코더)가 요즘과 같이 쉽게 UTF-8을 쉽게 처리 할 수있는 레이어 (또는 pragma)가 필요한 이유입니다.

tchrist 은 많은 면모를 지적하면서, 나는 며칠 또는 몇 주 동안 그들에 관해 읽고 생각할 것이다. 아직도, 이것은 나의 요지가 아니다. tchrist 는 "UTF-8을 가능하게하는 하나의 방법"이 없다는 것을 증명하려고 시도합니다. 나는 그것으로 논쟁 할 지식이별로 없다. 그래서 저는 살아있는 예를 고집합니다.

나는 Rakudo 와 함께 놀았고 UTF-8은 내가 필요한만큼 거기에 있었다. 나는 아무런 문제도 없었고 그냥 효과가 있었다. 아마 어딘가에 더 깊은 제한이있을 수 있지만, 처음에는 테스트 한 모든 것이 예상대로 작동했습니다.

현대 Perl 5에서도 이것이 목표가되어서는 안됩니까? 나는 더 강조했다 : 핵심 Perl을위한 기본 문자 세트로 UTF-8을 제안하지는 않는다. 새로운 프로젝트를 개발하는 사람들을 위해 스냅사용 하여 트리거 할 수있는 가능성을 제안한다.

또 다른 예이지만 더 부정적인 톤이 있습니다. 프레임 워크는 개발을 쉽게해야합니다. 몇 년 전에 웹 프레임 워크를 사용해 보았지만 "UTF-8 사용"이 너무 모호하여 웹 사이트를 버렸습니다. 유니 코드 지원 방법 및 위치를 찾지 못했습니다. 너무 오래 걸려서 옛날 방식으로가는 것이 더 쉬웠습니다. 이제 나는 Mason 2와 동일한 문제를 다루는 현상금이 있다는 것을 보았습니다. Mason2 UTF-8을 깨끗하게 만드는 방법은 무엇입니까? . 그래서, 꽤 새로운 프레임 워크이지만 UTF-8과 함께 사용하면 내부에 대한 깊은 지식이 필요합니다. 그것은 큰 빨간 표시와 같습니다 STOP, 나를 사용하지 마십시오!

나는 Perl을 정말 좋아한다. 그러나 유니 코드를 다루는 것은 고통 스럽습니다. 나는 여전히 벽을 향해 달려있다. 어떤면에서는 tchrist 가 옳았고 제 질문에 대한 해답을 제시합니다. 새로운 프로젝트는 Perl 5에서 너무 복잡하기 때문에 UTF-8을 끌어 들이지 않습니다.




I think you misunderstand Unicode and its relationship to Perl. No matter which way you store data, Unicode, ISO-8859-1 , or many other things, your program has to know how to interpret the bytes it gets as input (decoding) and how to represent the information it wants to output (encoding). Get that interpretation wrong and you garble the data. There isn't some magic default setup inside your program that's going to tell the stuff outside your program how to act.

You think it's hard, most likely, because you are used to everything being ASCII. Everything you should have been thinking about was simply ignored by the programming language and all of the things it had to interact with. If everything used nothing but UTF-8 and you had no choice, then UTF-8 would be just as easy. But not everything does use UTF-8. For instance, you don't want your input handle to think that it's getting UTF-8 octets unless it actually is, and you don't want your output handles to be UTF-8 if the thing reading from them can handle UTF-8. Perl has no way to know those things. That's why you are the programmer.

I don't think Unicode in Perl 5 is too complicated. I think it's scary and people avoid it. There's a difference. To that end, I've put Unicode in Learning Perl, 6th Edition , and there's a lot of Unicode stuff in Effective Perl Programming . You have to spend the time to learn and understand Unicode and how it works. You're not going to be able to use it effectively otherwise.




There's a truly horrifying amount of ancient code out there in the wild, much of it in the form of common CPAN modules. I've found I have to be fairly careful enabling Unicode if I use external modules that might be affected by it, and am still trying to identify and fix some Unicode-related failures in several Perl scripts I use regularly (in particular, iTiVo fails badly on anything that's not 7-bit ASCII due to transcoding issues).