유니 코드 텍스트 처리에는 두 단계가 있습니다. 첫 번째는 "정보를 잃지 않고 어떻게 입력하고 출력 할 수 있는가"입니다. 두 번째는 "지역 언어 규칙에 따라 텍스트를 처리하는 방법"입니다.
tchrist의 게시물은 두 가지를 모두 다루지 만 두 번째 부분은 게시물의 텍스트의 99 %가 나오는 곳입니다. 대부분의 프로그램은 I / O를 올바르게 처리하지 않으므로 정규화 및 데이터 정렬에 대해 걱정하기 전에 이해해야합니다.
이 게시물은 첫 번째 문제를 해결하는 것을 목표로합니다.
Perl로 데이터를 읽을 때 어떤 인코딩인지는 신경 쓰지 않습니다. 메모리를 할당하고 거기에 바이트를 숨 깁니다. 당신이 말하는 경우print $str
터미널에 해당 바이트가 블리트됩니다. 아마도 작성된 모든 것이 UTF-8이라고 가정하고 텍스트가 표시됩니다.
기이.
그렇지 않다. 데이터를 텍스트로 취급하려고하면 뭔가 잘못되었다는 것을 알 수 있습니다. length
펄이 당신의 줄에 대해 생각하는 것과 당신의 줄에 대해 어떻게 생각 하는지를 더 이상 보지 않아도 됩니다. 다음 perl -E 'while(<>){ chomp; say length }'
과 같은 한 줄짜리를 작성 하고 입력 文字化け
하면 12 ... 정답이 아닙니다.
펄은 문자열이 텍스트가 아니라고 가정하기 때문입니다. 텍스트가 올바른 답변을 제공하기 전에 텍스트임을 알려 주어야합니다.
충분히 쉽습니다. 인코딩 모듈에는이를 수행하는 기능이 있습니다. 일반 진입 점입니다 Encode::decode
(또는use Encode qw(decode)
물론)입니다. 이 함수는 외부 세계에서 문자열을 가져 와서 ( "8 비트 바이트"라고하는 멋진 표현 인 "옥텟"이라고 함) 펄이 이해할 수있는 텍스트로 바꿉니다. 첫 번째 인수는 "UTF-8"또는 "ASCII"또는 "EUC-JP"와 같은 문자 인코딩 이름입니다. 두 번째 인수는 문자열입니다. 리턴 값은 텍스트를 포함하는 Perl 스칼라입니다.
Encode::decode_utf8
인코딩 에도 UTF-8이 있다고 가정합니다.
원 라이너를 다시 작성하면 다음과 같습니다.
perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'
우리는 文字 化 け를 입력하고 결과적으로 "4"를 얻습니다. 성공.
이것이 바로 Perl에서 99 %의 유니 코드 문제에 대한 해결책입니다.
핵심은 프로그램에 텍스트가 올 때마다 해독해야한다는 것입니다. 인터넷은 문자를 전송할 수 없습니다. 파일은 문자를 저장할 수 없습니다. 데이터베이스에 문자가 없습니다. 옥텟 만 있으며 Perl에서 옥텟을 문자로 취급 할 수 없습니다. 인코딩 모듈을 사용하여 인코딩 된 옥텟을 Perl 문자로 디코딩해야합니다.
문제의 나머지 절반은 프로그램에서 데이터를 가져 오는 것입니다. 쉬운 일입니다. 당신은 단지 말을 use Encode qw(encode)
인코딩 데이터가 (UTF-8, UTF-16 Windows에서 파일 등 이해 단자에 UTF-8)에 일 무슨 결정, 그리고 다음 출력 결과 encode($encoding, $data)
대신 출력 $data
.
이 작업은 프로그램이 작동하는 Perl의 문자를 외부 세계에서 사용할 수있는 옥텟으로 변환합니다. 인터넷이나 터미널로 문자를 보낼 수 있다면 훨씬 쉬울 것입니다. 그러나 옥텟 만 가능합니다. 따라서 문자를 8 진수로 변환해야합니다. 그렇지 않으면 결과가 정의되지 않습니다.
요약하면 : 모든 출력을 인코딩하고 모든 입력을 디코딩합니다.
이제 우리는 이것을 조금 어렵게 만드는 세 가지 문제에 대해 이야기 할 것입니다. 첫 번째는 라이브러리입니다. 텍스트를 올바르게 처리합니까? 대답은 ... 그들이 시도하는 것입니다. 웹 페이지를 다운로드하면 LWP가 결과를 텍스트로 다시 제공합니다. 결과에 대해 올바른 메소드를 호출하면 (즉 , 서버에서 가져온 8 진수 스트림이 decoded_content
아닌 content
) 데이터베이스 드라이버가 비정상적 일 수 있습니다. Perl과 함께 DBD :: SQLite를 사용하면 제대로 작동하지만 다른 도구가 텍스트를 UTF-8 이외의 인코딩으로 저장된 텍스트를 데이터베이스에 저장하면 ... 잘 처리되지 않습니다. 코드를 올바르게 처리 할 때까지
데이터를 출력하는 것이 일반적으로 더 쉽지만 "인쇄의 와이드 문자"가 표시되면 인코딩을 어지럽히는 것입니다. 이 경고는 "이봐, 펄 캐릭터를 외부 세계로 유출 시키려고하는데 말이되지 않는다"는 뜻입니다. 다른 쪽 끝은 일반적으로 원시 Perl 문자를 올바르게 처리하기 때문에 프로그램이 작동하는 것처럼 보이지만 매우 손상되어 언제든지 작동을 멈출 수 있습니다. 명시 적으로 수정하십시오 Encode::encode
!
두 번째 문제는 UTF-8로 인코딩 된 소스 코드입니다. use utf8
각 파일의 상단에 말하지 않으면 Perl은 소스 코드가 UTF-8이라고 가정하지 않습니다. 이것은 당신이 무언가를 말할 때마다 my $var = 'ほげ'
프로그램에 쓰레기를 주입하여 모든 것을 완전히 무너 뜨릴 것임을 의미합니다. "utf8"을 사용할 필요는 없지만, 사용 하지 않으면 프로그램에서 ASCII가 아닌 문자를 사용 해서는 안됩니다.
세 번째 문제는 Perl이 과거를 처리하는 방법입니다. 오래 전에 유니 코드와 같은 것은 없었으며 Perl은 모든 것이 라틴어 -1 텍스트 또는 이진이라고 가정했습니다. 따라서 데이터가 프로그램에 들어 와서 텍스트로 취급하기 시작하면 Perl은 각 옥텟을 라틴 -1 문자로 취급합니다. 그래서 우리가 "文字 化 け"의 길이를 물었을 때 12를 얻었습니다. Perl은 라틴 -1 문자열 "æååã"(12 자, 일부는 인쇄가 아님)에서 작동한다고 가정했습니다.
이것을 "암시 적 업그레이드"라고하며, 완벽하게 합리적이지만 텍스트가 라틴 -1이 아닌 경우 원하는 것이 아닙니다. 그렇기 때문에 입력을 명시 적으로 디코딩하는 것이 중요합니다. 입력하지 않으면 Perl이이를 수행 할 수 있습니다.
데이터의 절반이 적절한 문자열이고 일부는 여전히 이진 인 경우 문제가 발생합니다. Perl은 여전히 이진 인 부분을 라틴 -1 텍스트 인 것처럼 해석 한 다음 올바른 문자 데이터와 결합합니다. 이렇게하면 캐릭터를 올바르게 처리하는 것이 프로그램을 깨뜨린 것처럼 보이지만 실제로는 충분히 수정하지 못했습니다.
예를 들면 다음과 같습니다. UTF-8로 인코딩 된 텍스트 파일을 읽는 프로그램이 있고 PILE OF POO
각 줄에 유니 코드 를 붙여 인쇄합니다. 다음과 같이 작성하십시오.
while(<>){
chomp;
say "$_ 💩";
}
그런 다음 다음과 같은 UTF-8 인코딩 데이터에서 실행하십시오.
perl poo.pl input-data.txt
각 줄의 끝에 똥을 사용하여 UTF-8 데이터를 인쇄합니다. 완벽합니다, 내 프로그램이 작동합니다!
그러나 아닙니다, 당신은 이진 연결을하고 있습니다. 파일에서 8 진수를 읽고 \n
with with chomp를 제거한 다음 PILE OF POO
문자 의 UTF-8 표현에서 바이트를칩니다 . 파일에서 데이터를 디코딩하고 출력을 인코딩하도록 프로그램을 수정하면 똥 대신 가비지 ( "ð ©")가 표시됩니다. 입력 파일을 디코딩하는 것은 잘못된 일이라고 믿게됩니다. 그렇지 않습니다.
문제는 똥이 라틴 -1로 암시 적으로 업그레이드되고 있다는 것입니다. 당신이 경우 use utf8
바이너리 대신 문자 텍스트를 만들기 위해, 그것은 다시 작동합니다!
(이것이 유니 코드를 가진 사람들을 도울 때 내가 겪는 가장 큰 문제입니다. 그들이 제대로하고 프로그램을 깨뜨 렸습니다. 그것은 정의되지 않은 결과에 대한 슬픈 일입니다. 오랫동안 일하는 프로그램을 가질 수 있지만 수리를 시작할 때, 걱정하지 마십시오. 프로그램에 인코딩 / 디코딩 문을 추가하고 중단하면 더 많은 작업이 필요하다는 의미 일뿐입니다. 다음에 유니 코드를 염두에두고 디자인 할 때는 처음부터 시작됩니다. 훨씬 쉽게!)
펄과 유니 코드에 대해 알아야 할 전부입니다. 데이터가 무엇인지 Perl에 알려 주면 모든 인기있는 프로그래밍 언어 중에서 최고의 유니 코드를 지원합니다. 그러나 어떤 종류의 텍스트를 공급하고 있는지 마술처럼 알고 있다고 가정하면 데이터를 취소 할 수 없게됩니다. 프로그램이 오늘날 UTF-8 터미널에서 작동한다고해서 내일 UTF-16으로 인코딩 된 파일에서 작동한다는 의미는 아닙니다. 이제 안전을 유지하고 사용자 데이터를 낭비하는 두통을 피하십시오!
유니 코드 처리의 쉬운 부분은 인코딩 출력 및 디코딩 입력입니다. 어려운 부분은 모든 입력 및 출력을 찾고 어떤 인코딩인지 결정하는 것입니다. 그러나 이것이 큰 돈을 얻는 이유입니다. :)