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




(7)

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에서도 이것이 목표가되어서는 안됩니까? 나는 더 강조한다. 핵심 펄에 대한 기본 문자 세트로 UTF-8을 제안하는 것이 아니며, 새로운 프로젝트를 개발하는 사람들을 위해 스냅 으로 트리거 할 수있는 가능성을 제안한다.

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

나는 Perl을 정말 좋아한다. 그러나 유니 코드를 다루는 것은 고통 스럽습니다. 나는 여전히 벽을 향해 달려있다. 어떤면에서는 tchrist 가 옳았고 제 질문에 대한 해답을 제시합니다. 새로운 프로젝트는 Perl 5에서 너무 복잡하기 때문에 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 인코딩 된 파일로 작동한다는 것을 의미하지는 않습니다. 이제 안전하게 만들어 보시고 사용자의 데이터를 파괴하는 두통을 피하십시오!

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


🌴 🐪🐫🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪

𝓔𝓭𝓲𝓽 : 𝙎𝙞𝙢𝙥𝙡𝙚𝙨𝙩 : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚

  1. PERL_UNICODE envariable을 AS 설정하십시오. 이렇게하면 모든 Perl 스크립트가 @ARGV 를 UTF-8 문자열로 디코드하고 stdin, stdout 및 stderr 세 가지 모두의 인코딩을 UTF-8로 설정합니다. 두 가지 모두 어휘 적 효과가 아니라 전체 효과입니다.

  2. 소스 파일 (프로그램, 모듈, 라이브러리, 히키 키)의 맨 위에 다음을 통해 perl 버전 5.12 이상이 실행되고 있음을 눈여겨보아야합니다.

    use v5.12; # minimal for unicode string feature

    use v5.14; # optimal for unicode string feature

  3. 이전 선언은 경고가 아닌 협약 및 기능 만 사용하므로 경고를 활성화하십시오. 또한 유니 코드 경고를 예외로 승격시키는 것이 좋습니다.이 중 하나뿐 아니라 두 행을 모두 사용하십시오. 그러나 v5.14에서 utf8 경고 클래스는 nonchar , surrogatenon_unicodenon_unicode 세 가지 하위 경고를 모두 별도로 사용할 수 있습니다. 이것들을보다 잘 제어 할 수 있습니다.

    use warnings;

    use warnings qw( FATAL utf8 );

  4. 이 소스 단위가 UTF-8로 인코딩되어 있다고 선언하십시오. 옛날 옛적에이 pragma가 다른 일을했지만, 이제는이 하나의 단 하나의 목적만을 제공합니다.

    use utf8;

  5. 이 어휘 범위 내 에서 파일 핸들을 여는 것은 무엇이든 선언 하지만 다른 곳에서는 그렇지 않다는 것을 선언 하지 않으면 스트림이 UTF-8로 인코딩되었다고 가정하는 것입니다. 그렇게하면 다른 모듈이나 다른 프로그램의 코드에는 영향을 미치지 않습니다.

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

  6. \N{CHARNAME} 를) 통해 명명 된 문자를 사용하도록 설정합니다.

    use charnames qw( :full :short );

  7. DATA 핸들을 가지고 있다면 인코딩을 명시 적으로 설정해야합니다. 이것을 UTF-8로 원한다면 다음과 같이 말하십시오.

    binmode(DATA, ":encoding(UTF-8)");

당연히 자신이 우려할만한 다른 문제는 끝나지 않지만 이러한 목표에 대한 다소 약화 된 의미는 있지만 "UTF-8로 모든 것이 제대로 작동하도록"국가 목표를 대략적으로 설명하는 것으로 충분합니다.

하나의 다른 pragma는 유니 코드와 관련이 없지만 다음과 같습니다.

      use autodie;

강력히 권합니다.

🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 𝖙 🎅

"Perl은 [ 어쨌든! ] 유니 코드를 기본값으로 사용 가능하게 설정하는 것조차도 드물지만 고립 된 경우에 유용하게 사용할 수있을만큼 충분히 말하기에 대해 생각하기 시작하지 않습니다. 유니 코드는 단순히 더 큰 문자 레퍼토리 이상입니다. 또한 이러한 문자들이 모두 여러 가지 방식으로 상호 작용하는 방식이기도합니다.

사람들이 원하는 것으로 생각하는 단순한 최소한의 조치조차도 수백만 줄의 코드를 비참하게 깨뜨릴 수 있습니다. 코드는 새로운 멋진 새로운 세계의 근대성을 "업그레이드"할 기회가 없습니다.

그것은 사람들이 가장하는 것보다 훨씬 더 복잡합니다. 지난 몇 년 동안 나는 이것에 대해 엄청나게 많은 생각을 해왔습니다. 나는 내가 틀렸다는 것을 보여주고 싶다. 그러나 나는 생각하지 않는다. 유니 코드는 근본적으로 당신이 그것에 부과하고자하는 모델보다 더 복잡하며, 여기서 당신은 결코 카펫 밑을 쓸어 갈 수 없다는 복잡성이 있습니다. 시도하면 자신의 코드 또는 다른 사람의 코드를 깨뜨릴 수 있습니다. 어느 시점에서, 당신은 간단히 말해서 유니 코드가 무엇인지를 알아야합니다. 그것이 아닌 것으로 가장 할 수는 없습니다.

🐪 내가 사용한 적이있는 것보다 훨씬 더 쉽게 유니 코드를 쉽게 만들 수 있습니다. 이것이 나쁘다고 생각하면 잠시 다른 것을 시도하십시오. 그런 다음 back로 돌아 오십시오 : 당신이 더 나은 세상으로 돌아갈 지 아니면 다른 사람에게도 지식을 가져다 줄 것입니다. 그래서 우리는 당신의 새로운 지식을 활용하여 이러한 것들을 더 잘 만들 수 있습니다.

💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖎𝖘𝖙

최소한 다음과 같이 🐪가 "기본적으로 유니 코드를 사용 가능하게"설정하는 데 필요한 것으로 보이는 것들이 있습니다 :

  1. 모든 소스 코드는 기본적으로 UTF-8이어야합니다. use utf8use utf8 하거나 export PERL5OPTS=-Mutf8use utf8 얻을 수 있습니다.

  2. 🐪 DATA 핸들은 UTF-8이어야합니다. binmode(DATA, ":encoding(UTF-8)") 와 같이 패키지 단위로이 작업을 수행해야합니다.

  3. 스크립트에 대한 프로그램 인수는 기본적으로 UTF-8로 이해해야합니다. perl -CA export PERL_UNICODE=A 또는 perl -CAexport PERL5OPTS=-CA 거나 export PERL5OPTS=-CA .

  4. 표준 입력, 출력 및 오류 스트림은 기본적으로 UTF-8이어야합니다. export PERL_UNICODE=S 를 모두 export PERL_UNICODE=S 거나, 그 중 일부만 I , O 및 / 또는 Eexport PERL_UNICODE=S . 이것은 perl -CS 와 같습니다.

  5. by로 열린 다른 핸들은 다르게 선언하지 않는 한 UTF-8로 간주되어야합니다. export PERL_UNICODE=D 거나 이들 중 특정 항목에 대해 io 를 사용합니다. export PERL5OPTS=-CD 가 작동합니다. 그것은 모든 사람들에게 -CSAD 를 만듭니다.

  6. 두베이스와 함께 열려있는 모든 스트림을 export PERL5OPTS=-Mopen=:utf8,:stdexport PERL5OPTS=-Mopen=:utf8,:std 수 있습니다. uniquote 참조하십시오.

  7. UTF-8 인코딩 오류를 놓치지 않으려 고합니다. export PERL5OPTS=-Mwarnings=FATAL,utf8 . 그리고 입력 스트림이 :utf8 뿐만 아니라 항상 binmode d :encoding(UTF-8) 인지 확인하십시오.

  8. 128-255 사이의 코드 포인트는 정의되지 않은 2 진 값이 아닌 해당 유니 코드 코드 포인트가되도록 by에 의해 이해되어야합니다. use feature "unicode_strings" 하거나 export PERL5OPTS=-Mfeature=unicode_strings . 그러면 uc("\xDF") eq "SS""\xE9" =~ /\w/ 됩니다. 간단한 export PERL5OPTS=-Mv5.12 또는 그 이상도 얻을 수 있습니다.

  9. 명명 된 유니 코드 문자는 기본적으로 활성화되어 있지 않으므로 export PERL5OPTS=-Mcharnames=:full,:short,latin,greek 또는 일부를 추가하십시오. uninamestcgrep 참조하십시오.

  10. 대부분의 경우 표준 Unicode::Normalize 모듈의 다양한 유형의 분해에 대한 함수에 액세스해야합니다. export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD 를 내 보낸 다음 항상 NFD를 통해 들어오는 내용을 실행하고 NFC의 아웃 바운드 내용을 실행합니다. 이들에 대한 I / O 레이어는 아직 없지만 nfc , nfd , nfkdnfkc 참조하십시오.

  11. eq , ne , lc , cmp , sort , & cc를 사용하는 in의 문자열 비교는 항상 잘못되었습니다. 따라서 @a = sort @b 대신 @a = Unicode::Collate->new->sort(@b) 합니다. export PERL5OPTS=-MUnicode::Collate 추가 할 수도 있습니다. 이진 비교를 위해 키를 캐싱 할 수 있습니다.

  12. printf 와 같은 내장 printf 는 유니 코드 데이터로 잘못된 작업을 수행합니다. 이전 에는 Unicode::GCString 모듈 을 사용해야 하며 , Unicode::LineBreak 모듈 뿐 아니라 후자를 위해 Unicode::GCString 모듈 을 사용해야 합니다 . uwcunifmt 참조하십시오.

  13. 정수로 간주하기를 원한다면, 🐪의 내장 atoi (3)가 현재 충분히 영리하지 않기 때문에 Unicode::UCD::num 함수를 통해 \d+ 캡처를 실행해야합니다.

  14. 파일 시스템에 파일 시스템 문제가있을 것입니다. 일부 파일 시스템은 자동으로 NFC 로의 변환을 시행합니다. 다른 사람들은 조용히 NFD 로의 전환을 시행합니다. 그리고 다른 사람들은 아직도 다른 것을합니다. 심지어 어떤 사람들은 그 문제를 모두 무시하기 때문에 더 큰 문제가 발생합니다. 따라서 당신은 자신의 NFC / NFD 처리를해야 정성을 유지할 수 있습니다.

  15. m// , s///tr/// 포함하여 az 또는 AZ 와 관련된 모든 코드가 변경되어야합니다. 코드가 손상되었다는 비명을 지르는 붉은 깃발처럼 눈에 띄는 것이 좋습니다. 그러나 그것이 어떻게 변해야하는지 명확하지 않다. 올바른 속성을 얻고 케이스 폴드를 이해하는 것이 생각보다 어렵습니다. 나는 매일 unicharsuniprops 사용한다.

  16. \p{Lu} 를 사용하는 코드는 [A-Za-z] 를 사용하는 코드와 거의 같습니다. 대신에 \p{Upper} 를 사용해야하고 그 이유를 알아야합니다. 예, \p{Lowercase}\p{Lower}\p{Ll}\p{Lowercase_Letter} 과 다릅니다.

  17. [a-zA-Z] 를 사용 [a-zA-Z] 코드는 더욱 심각합니다. 그리고 \pL 또는 \p{Letter} 사용할 수 없습니다. \p{Alphabetic} 를 사용해야합니다. 모든 문자표가 글자가 아닙니다.

  18. /[\$\@\%]\w+/ 변수를 찾고 있다면 문제가있는 것입니다. /[\$\@\%]\p{IDS}\p{IDC}*/ 를 찾아야합니다. 구두점 변수 나 패키지 변수를 고려하지 않아도됩니다.

  19. 공백을 검사하는 경우에는 \h\v 중에서 선택해야합니다. 그리고 대중적인 믿음과는 달리 [\h\v] 하지 않으므로 \s 는 사용 하지 않아야 합니다.

  20. 선 경계 나 \r\n \n 위해 \n 을 사용하고 있다면 잘못하고있는 것입니다. 당신은 \R 을 사용해야합니다. 이것은 동일하지 않습니다!

  21. Unicode::Stringprep 을 호출 Unicode::Stringprep 을 호출 할지를 잘 모르는 경우 배우십시오.

  22. 대소 문자를 구분하지 않는 비교는 발음 구별 기호 등이 무엇이든 상관없이 두 문자가 같은 문자인지 확인해야합니다. 가장 쉬운 방법은 표준 Unicode :: Collate 모듈을 사용하는 것입니다. Unicode::Collate->new(level => 1)->cmp($a, $b) . 또한 eq 메소드 등이 있으며 matchsubstr 메소드에 대해서도 배워야합니다. 이것들은 내장형에 비해 뚜렷한 이점을 가지고 있습니다.

  23. 때로는 여전히 충분하지 않으며 Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b)같이 Unicode :: Collate :: Locale 모듈이 필요 합니다. Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b) 대신 사용하십시오. Unicode::Collate::->new(level => 1)->eq("d", "ð") 가 참이지만 Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð") 는 거짓입니다. 마찬가지로 로케일을 사용하지 않거나 영어를 사용하는 경우 "ae"및 "æ"는 eq 이지만 아이슬란드 어 로켈에서는 다릅니다. 이제 뭐? 힘들어. 너에게 말한다. 이러한 것들을 테스트하기 위해 unifmt 로 게임을 할 수 있습니다.

  24. " niño "문자열에서 CVCV (자음, 모음, 자음, 모음) 패턴을 일치시키는 방법을 고려하십시오. 그것의 NFD 형식 - 당신이 잘 기억하는 것이 기억하기를 "- nin \ x {303} o"이됩니다. 이제 어떻게 할거 니? 심지어 모음이 [aeiou] 것처럼 (심지어는 잘못 [aeiou] ), NFD 에서조차도 (?=[aeiou])\X) '와 같은 코드 포인트가 있기 때문에 당신은 (?=[aeiou])\X) 와 같은 것을 할 수 없을 것입니다. ø ' 분해하지 않습니다 ! 그러나 방금 설명한 UCA 비교를 사용하여 'o'와 동일하게 테스트합니다. NFD에 의지 할 수는 없으며 UCA에 의존해야합니다.

💩 𝔸 𝕤 𝕤 𝕦 𝕞 𝕖 𝔹 𝕣 𝕠 𝕜 𝕖 𝕟 𝕟 𝕖 𝕤 𝕤 💩

그리고 그게 전부가 아닙니다. 사람들이 유니 코드에 관해 만드는 백만 가지의 잘못된 가정이 있습니다. 그들이 이러한 것들을 이해할 때까지, 그들의 코드는 깨질 것입니다.

  1. 인코딩을 지정하지 않고 텍스트 파일을 열 수 있다고 가정하는 코드는 깨졌습니다.

  2. 기본 인코딩이 일종의 기본 플랫폼 인코딩이라고 가정하는 코드가 손상되었습니다.

  3. 일본어 또는 중국어 웹 페이지가 UTF-16보다 UTF-16에서 차지하는 공간이 적다 고 가정하는 코드가 잘못되었습니다.

  4. Perl이 내부적으로 UTF-8을 사용한다고 가정하는 코드는 잘못되었습니다.

  5. 인코딩 오류가 항상 예외를 발생시키는 것으로 가정하는 코드는 잘못되었습니다.

  6. Perl 코드 포인트가 0x10_FFFF로 제한되어 있다고 가정하는 코드는 잘못되었습니다.

  7. $/ 를 유효한 줄 구분 기호와 함께 사용할 수있는 것으로 가정하는 코드가 잘못되었습니다.

  8. lc(uc($s)) eq $s 또는 uc(lc($s)) eq $s 와 같이 casefolding시 왕복 동등성을 가정하는 코드는 완전히 손상되고 잘못되었습니다. uc("σ")uc("ς") 는 둘 다 "Σ" 이지만 lc("Σ") 는 둘 다 반환 할 수 없다고 생각하십시오.

  9. 모든 소문자 코드 포인트에 고유 한 대문자가 있다고 가정하는 코드 또는 그 반대의 경우도 파손됩니다. 예를 들어 "ª" 는 대문자가없는 소문자입니다. 반면에 "ᵃ""ᴬ" 는 모두 문자이지만 소문자가 아닙니다. 그러나 이들은 대문자 버전이없는 소문자 코드 포인트입니다. 알았어? \p{Letter}\p{Lowercase} 임에도 불구하고 \p{Lowercase_Letter}아닙니다 .

  10. 대소 문자를 변경한다고 가정하는 코드는 문자열의 길이가 변경되지 않습니다.

  11. 단 2 건만 있다고 가정하는 코드는 깨졌습니다. 타이틀 케이스도 있습니다.

  12. 문자만으로 대소 문자가 구분 된 코드입니다. 단순한 문자 외에도 숫자, 기호 및 짝수 기호는 대소 문자가 구분됩니다. 사실, 대소 문자를 변경하면 \p{Mark}\p{Letter} 로 바뀌는 것과 같은 주요 카테고리로 변경 될 수도 있습니다. 또한 한 스크립트에서 다른 스크립트로 전환 할 수 있습니다.

  13. 대 / 소문자가 로캘에 종속되지 않는다고 가정하는 코드는 손상되었습니다.

  14. 유니 코드가 POSIX 로케일에 관한 그림을 제공한다고 가정하는 코드가 손상되었습니다.

  15. 기본 ASCII 문자를 얻기 위해 구별 부호를 제거 할 수 있다고 가정하는 코드는 악조건, 여전히 손상, 뇌 손상, 잘못, 사형에 대한 정당화입니다.

  16. 분음 부호 \p{Diacritic} 기호 \p{Diacritic}\p{Mark} 기호 \p{Mark} 가 같은 것을 나타내는 코드는 깨졌습니다.

  17. \p{GC=Dash_Punctuation}\p{Dash} 만큼 \p{GC=Dash_Punctuation} 것으로 간주하는 코드가 손상되었습니다.

  18. 대시, 하이픈 및 빼기가 서로 동일하거나 또는 하나만 있다고 가정하는 코드는 손상되고 잘못되었습니다.

  19. 모든 코드 포인트가 하나 이상의 인쇄 열을 차지하지 않는다고 가정하는 코드는 손상되었습니다.

  20. 모든 \p{Mark} 문자가 0 인쇄 열을 차지한다고 가정하는 코드가 손상되었습니다.

  21. 비슷하게 보이는 문자 모두 동일하다고 가정하는 코드입니다.

  22. 비슷하게 보이지 않는 문자가 비슷하지 않다고 가정하는 코드가 손상되었습니다.

  23. 하나의 \X 만 일치 할 수있는 행의 코드 포인트 수에 제한이 있다고 가정하는 코드가 잘못되었습니다.

  24. \X\p{Mark} 문자로 시작될 수 없다고 가정하는 코드가 잘못되었습니다.

  25. \X 가 두 개의 \p{Mark} 문자를 절대로 가질 수 없다고 가정하는 코드가 잘못되었습니다.

  26. "\x{FFFF}" 사용할 수 없다고 가정하는 코드가 잘못되었습니다.

  27. 두 개의 UTF-16 (대용) 코드 단위를 필요로하는 비 BMP 코드 포인트가 코드 단위당 하나씩 두 개의 별도 UTF-8 문자로 인코딩된다는 가정은 잘못된 것입니다. 그렇지 않습니다. 단일 코드 포인트로 인코딩됩니다.

  28. UTF-16 또는 UTF-32에서 주요 BOM과 함께 UTF-8로 코드 변환하는 코드는 결과 UTF-8의 시작 부분에 BOM을 넣으면 손상됩니다. 이것은 엔지니어가 눈꺼풀을 제거해야하는 매우 어리 석다.

  29. CESU-8이 유효한 UTF 인코딩이라고 가정하는 코드가 잘못되었습니다. 마찬가지로, U + 0000을 "\xC0\x80" 으로 인코딩하는 것이 UTF-8이라고 생각하는 코드는 "\xC0\x80" 하고 잘못되었습니다. 이 녀석들도 눈꺼풀 치료를 받아야합니다.

  30. > 와 같은 문자는 항상 오른쪽을 가리키고 < 항상 왼쪽을 가리키는 코드는 잘못되었습니다. 실제로는 그렇지 않습니다.

  31. 처음 문자 X 출력 한 다음 문자 Y 를 출력하고, 그 문자가 XY 로 표시된다고 가정하는 코드입니다. 때로는 그렇지 않습니다.

  32. ASCII가 영어를 적절하게 작성하기에 충분하다고 가정하는 코드는 어리 석고, 근시안적인 것이며, 문맹자이며, 부러워서, 악하고, 잘못되었습니다. 그들의 머리에 떨어져! 그것이 너무 극단적 인 경우, 우리는 타협 할 수 있습니다 : 이후 그들은 한발에서 자신의 엄지 발가락으로 만 입력 할 수 있습니다 (나머지는 여전히 ducktaped됩니다).

  33. 모든 \p{Math} 코드 포인트가 보이는 문자라고 가정하는 코드가 잘못되었습니다.

  34. \w 가 문자, 숫자 및 밑줄 만 포함한다고 가정하는 코드가 잘못되었습니다.

  35. ^~ 이 구두점임을 가정하는 코드는 잘못되었습니다.

  36. 움라우트가 있다고 가정하는 코드는 잘못되었습니다.

  37. 와 같은 문자가 포함되어 있다고 생각하는 코드는 잘못되었습니다.

  38. \p{InLatin}\p{Latin}\p{InLatin} 믿는 코드는 크게 손상되었습니다.

  39. \p{InLatin} 이 거의 유용하다고 믿는 코드는 거의 틀림없이 잘못된 것입니다.

  40. [${FIRST_LETTER}-${LAST_LETTER}] 는 어떤 알파벳 $LAST_LETTER 첫 글자로 주어진 마지막 알파벳과 $LAST_LETTER 가 같은 알파벳의 마지막 글자로 주어 졌다고 믿는 코드는 거의 항상 [${FIRST_LETTER}-${LAST_LETTER}] 하고 잘못되었습니다. 무의미한.

  41. 누군가의 이름에 특정 문자 만 포함될 수 있다고 생각하는 코드는 어리 석고 공격적이며 잘못되었습니다.

  42. 유니 코드를 ASCII로 줄이려고하는 코드는 단순히 잘못된 것이 아니며 가해자가 다시 프로그래밍 할 때 사용해서는 안됩니다. 기간. 나는 심지어 긍정적으로 생각하지도 않는다. 그들은 다시 볼 수 있도록 허용해야한다. 분명히 지금까지 그렇게 잘하지 못했기 때문이다.

  43. 텍스트 파일 인코딩이 존재하지 않는다고 믿는 코드는 깨지기 쉽고 위험합니다. 다른 쪽 눈을 찌를 수도 있습니다.

  44. 알 수없는 문자를 변환하는 코드 ? 멍청하고, 멍청하고, 표준 권고에 위배된다 . RTFM 왜 안돼.

  45. 마크가없는 텍스트 파일의 인코딩을 안정적으로 추측 할 수 있다고 믿는 코드는 치명적인 오만한 오만함과 제우스의 번개 만 고칠 것입니다.

  46. 유니 코드 데이터를 채우고 정당화하기 위해 printf 너비를 사용할 수 있다고 생각하는 코드는 잘못되었거나 잘못되었습니다.

  47. 주어진 이름으로 파일을 성공적으로 생성하면, 그 디렉토리를 둘러싸고있는 디렉토리에서 lsreaddir 을 실행할 때 실제로 생성 된 파일 이름이 버그가 있고, 잘못되었고, 잘못되었다는 것을 알 수있는 코드입니다. 이것에 놀라지 마라!

  48. UTF-16이 고정 너비 인코딩이라고 생각하는 코드는 어리 석고 잘못되었거나 잘못되었습니다. 프로그래밍 라이센스를 철회하십시오.

  49. 한 비행기의 코드 포인트를 다른 비행기의 코드 포인트와 다르게 취급하는 코드는 사실상 고장 나고 잘못되었습니다. 학교에 다시가.

  50. /s/i 와 같은 내용이 "S" 또는 "s" 와 일치 할 수 있다고 생각하는 코드는 부적절하고 잘못되었습니다. 너는 놀랄거야.

  51. \X 를 사용하는 대신에 \PM\pM* 을 사용하여 제자 클러스터를 찾는 코드가 잘못되어 잘못되었습니다.

  52. ASCII 세계로 돌아가고 싶은 사람들은 전심으로 그렇게하도록 격려해야하며, 영광 스럽은 업 그레 이드를 기쁘게 생각 하여 모든 데이터 입력 요구에 대비하여 전기 사전 수동 타자기를 제공해야합니다. 그들에게 보낸 메시지는 한 줄당 40 자의 ᴀʟʟᴄᴀᴘ 전보를 통해 보내야하며 택배로 직접 배달해야합니다. 중지.

🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝕮𝖔𝖉𝖊 𝕮𝖔𝖉𝖊 🐪

요즘 제 자신의 상용구는 다음과 같이 보입니다.

use 5.014;

use utf8;
use strict;
use autodie;
use warnings; 
use warnings    qw< FATAL  utf8     >;
use open        qw< :std  :utf8     >;
use charnames   qw< :full >;
use feature     qw< unicode_strings >;

use File::Basename      qw< basename >;
use Carp                qw< carp croak confess cluck >;
use Encode              qw< encode decode >;
use Unicode::Normalize  qw< NFD NFC >;

END { close STDOUT }

if (grep /\P{ASCII}/ => @ARGV) { 
   @ARGV = map { decode("UTF-8", $_) } @ARGV;
}

$0 = basename($0);  # shorter messages
$| = 1;

binmode(DATA, ":utf8");

# give a full stack dump on any untrapped exceptions
local $SIG{__DIE__} = sub {
    confess "Uncaught exception: @_" unless $^S;
};

# now promote run-time warnings into stackdumped exceptions
#   *unless* we're in an try block, in which 
#   case just generate a clucking stackdump instead
local $SIG{__WARN__} = sub {
    if ($^S) { cluck   "Trapped warning: @_" } 
    else     { confess "Deadly warning: @_"  }
};

while (<>)  {
    chomp;
    $_ = NFD($_);
    ...
} continue {
    say NFC($_);
}

__END__

😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄

나는 "Unicode in default"가 내가 작성한 것보다 얼마나 많은 것을 얻을 수 있는지 알지 못한다. 네, 그렇습니다. Unicode::CollateUnicode::LineBreak 를 사용해야합니다. 아마 더.

알다시피, "유니 코드에 대한 기본 설정"과 같은 것들이 존재한다는 것을 실제로 염려해야하는 너무 많은 유니 코드 것들이 있습니다.

우리가 🐪 5.8에서했던 것처럼, 처음부터 제대로 설계되지 않은 코드에이 모든 것을 적용하는 것은 불가능하다는 것을 발견하게 될 것입니다. 당신의 선의의 이기심은 방금 전 세계를 파산 시켰습니다.

그리고 일단 그렇게하더라도 여전히 올바른 생각을하기 위해 많은 노력을 기울여야하는 중요한 문제가 있습니다. 뒤집을 수있는 스위치가 없습니다. 두뇌 만이 아니라, 나는 진정한 두뇌를 의미합니다. 여기서 충분할 것입니다. 배울 점이 많습니다. 수동 타자기를 퇴각시키지 않으면 무지로 몰래 들어가기를 바랄 수 없습니다. 이것은 21 세기입니다. 의도하지 않은 무지로 유니 코드를 버리고 싶지는 않습니다.

당신은 그것을 배워야합니다. 기간. "모든 것이 효과가있다"는 것이 그리 쉽지는 않을 것입니다. 왜냐하면 그것은 많은 것들이 작동 하지 않는다는 것을 보장 할 것이기 때문입니다. 그것은 "모든 것을 일하게 만들 수있는 방법"이 될 수 있다는 가정을 무효로 만듭니다.

몇 가지 매우 제한된 작업에 대해 합리적인 기본값을 얻을 수는 있지만 생각보다 훨씬 많은 것을 생각하지 않아도됩니다.

하나의 예로서, 표준 순서는 몇 가지 진짜 두통을 일으킬 것입니다. "\x{F5}" "o\x{303}" , "o\x{303}\x{304}" , "o\x{304}\x{303}" 'ō' 는 모두 'õ' 와 일치해야하지만, 어떻게 세상에서 그것을 할 것입니까? 이것은 보이는 것보다 더 힘들지만, 그것은 당신이 설명 할 필요가있는 것입니다. 💣

Perl에 대해 내가 아는 한 가지가 있다면, 그것은 유니 코드 비트가하는 것과하지 않는 것입니다. 그리고 나는 여러분에게 이것을 약속합니다 : "ᴛʜᴇʀᴇ ɪs ɴᴏ Uɴɪᴄᴏᴅᴇ ᴍᴀɢɪᴄ ʙᴜʟʟᴇᴛ" 😞

기본값을 변경하고 원활한 항해를 할 수는 없습니다. PERL_UNICODE를 "SA" 설정하여 run을 실행하는 것은 사실이지만, 그게 전부이며, 대부분 명령 줄의 내용이기도합니다. 실제 작업을 위해 위에서 설명한 많은 단계를 거치며 매우 신중하게 처리합니다.

😈 ƨ ƨ ƨ ɥ ɥ ƨᴉɥʇ ɥdoɥ puɐɐɐɐɐɐʌɐɥʞʞʞʞʞʞʞ


유니 코드와 Perl과의 관계를 오해한다고 생각합니다. 데이터, 유니 코드, ISO-8859-1 또는 다른 많은 것들을 저장하는 방법에 관계없이 프로그램은 입력 (디코딩)으로 가져온 바이트를 해석하고 출력하려는 ​​정보를 나타내는 방법을 알고 있어야합니다 (인코딩 ). 그 해석을 잘못 받아들이면 데이터가 왜곡됩니다. 프로그램 내에 마법의 기본 설정이 없으므로 프로그램 외부에서 작동 방법을 알릴 수 있습니다.

모든 것이 ASCII가되기 때문에 익숙하지 않을 수도 있습니다. 생각하고 있어야했던 모든 것은 프로그래밍 언어와 상호 작용해야하는 모든 것들에 의해 간단히 무시되었습니다. 모든 것이 UTF-8 만 사용하고 선택의 여지가 없다면 UTF-8도 마찬가지로 쉽습니다. 그러나 모든 것이 UTF-8을 사용하는 것은 아닙니다. 예를 들어, 입력 핸들이 실제로는 않는 한 UTF-8 8 중창을 얻는다고 생각하지 않아야하며, 출력 핸들이 UTF-8을 처리 할 수 ​​있다면 출력 핸들이 UTF-8이되는 것을 원하지 않을 것입니다 . Perl은 그런 것을 알 수있는 방법이 없습니다. 그래서 당신이 프로그래머입니다.

필자는 Perl 5의 유니 코드가 너무 복잡하다고 생각하지 않습니다. 나는 그것이 무섭다라고 생각한다. 그리고 사람은 그것을 피한다. 차이점이 있습니다. 이를 위해 Learning Perl, 6th Edition 에 유니 코드를 넣었 으며 효과적인 Perl 프로그래밍 에는 많은 유니 코드가 있습니다. 유니 코드를 배우고 이해하는 데 시간을 할애해야합니다. 당신은 그렇지 않으면 그것을 효과적으로 사용할 수 없을 것입니다.


이 스레드를 읽는 동안 사람들이 " Unicode " 와 동의어로 " UTF-8 "을 사용한다는 인상을받는 경우가 있습니다. ASCII 코드와 Unicode의 다양한 "인코딩"을 확대 한 유니 코드의 "코드 포인트"를 구분하십시오. UTF-8, UTF-16UTF-32 가 현재 사용되고 있으며 몇 가지가 더 이상 사용되지 않는 몇 가지가 있습니다.UnicodeUTF-16UTF-32

UTF-8 (다른 모든 인코딩 과 마찬가지로 )이 존재하며 입력 또는 출력에서만 의미가 있습니다. 내부적으로 Perl 5.8.1부터 모든 문자열은 유니 코드 "코드 포인트"로 유지됩니다. 사실 이전에 감탄 해 마지 않는 일부 기능을 활성화해야합니다.


우리는 모두 여러 가지 이유로 어려운 문제라고 동의합니다.하지만 모든 사람들이 더 쉽게 사용하도록하려는 이유입니다.

CPAN에는 utf8::all 이라는 최신 모듈이 있으며,이 모듈은 "유니 코드를 켜십시오. 모두"를 시도합니다.

지적했듯이, 마술처럼 전체 시스템 (외부 프로그램, 외부 웹 요청 등)도 유니 코드를 사용할 수는 없지만 함께 작업하여 일반적인 문제를 더 쉽게 만들어주는 합리적인 도구를 만들 수 있습니다. 이것이 우리가 프로그래머라는 이유입니다.

utf8 :: all이해야한다고 생각하는 것을하지 않으면, 그것을 개선하기 위해 그것을 개선합시다. 또는 가능한 한 사람의 다양한 요구에 함께 맞는 추가 도구를 만들어 봅시다.

`


야생 CPAN 모듈의 형태로 많은 고대 코드가 존재합니다. 필자가 영향을받을 수있는 외부 모듈을 사용하고 정기적으로 사용하는 여러 Perl 스크립트에서 일부 유니 코드 관련 오류를 확인하고 수정하려고 시도 할 때 유니 코드를 사용하도록주의를 기울여야한다는 것을 발견했습니다 (특히 iTiVo 실패합니다 트랜스 코딩 문제로 인해 7 비트 ASCII가 아닌 것에는 심하게 있습니다.)


보통 do 와 함께 사용되는 속임수입니다. perlsyn Statement Modifiers 장을 참조하십시오.

아마 저자는 next 과 같은 블록을 뛰어 넘기를 원했을 것입니다.





perl unicode utf-8