Perl을 사용하여 구축 된 대부분의 최신 솔루션 이 기본적으로 UTF-8 을 활성화하지 않는 이유가 궁금 합니다.
핵심 Perl 스크립트에 문제가 생길 수있는 많은 레거시 문제가 있음을 이해합니다. 그러나, 내 관점에서의 21 번째 세기, 큰 새로운 프로젝트 (또는 큰 관점 프로젝트는) 처음부터 자신의 소프트웨어 UTF-8 증거를해야한다. 여전히 나는 그것이 일어나는 것을 보지 못한다. 예를 들어, Moose 는 엄격한 경고를 활성화하지만 Unicode 는 활성화하지 않습니다 . 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, 나를 사용하지 마십시오!
나는 펄을 정말로 좋아한다. 그러나 유니 코드를 다루는 것은 고통 스럽습니다. 나는 아직도 나 자신이 벽에 부딪 치는 것을 발견한다. 어떤 방법으로 tchrist 가 옳고 내 질문에 대답합니다 : 새로운 프로젝트는 UTF-8이 Perl 5에서 너무 복잡하기 때문에 UTF-8을 끌지 않습니다.
답변
???????? ℞ : ? ???????? ???????????????
-
PERL_UNICODE
변수를로 설정하십시오AS
. 이렇게하면 모든 Perl 스크립트@ARGV
가 UTF-8 문자열로 디코딩 되고 stdin, stdout 및 stderr의 세 가지 인코딩이 모두 UTF-8로 설정됩니다. 둘 다 어휘 효과가 아닌 전역 효과입니다. -
소스 파일 (프로그램, 모듈, 라이브러리,
do
hickey) 의 맨 위에 다음을 통해 perl 5.12 이상 버전을 실행하고 있다고 분명히 주장하십시오.use v5.12; # minimal for unicode string feature use v5.14; # optimal for unicode string feature
-
이전 선언에서는 경고가 아닌 제한 및 기능 만 사용할 수 있으므로 경고를 사용하십시오. 또한 유니 코드 경고를 예외로 승격시키는 것이 좋습니다. 둘 중 하나만이 아니라 두 줄을 모두 사용하십시오. 참고 그러나 v5.14 아래 있음을
utf8
경고 클래스는 모든 별도로 사용할 수있는 세 가지 다른 subwarnings을 포함한다 :nonchar
,surrogate
,와non_unicode
. 이것들은 더 큰 통제력을 발휘하기를 원할 것입니다.use warnings; use warnings qw( FATAL utf8 );
-
이 소스 장치는 UTF-8로 인코딩되도록 선언하십시오. 옛날 옛적에이 pragma는 다른 일을했지만, 이제는이 하나의 유일한 목적을 위해서만 사용됩니다.
use utf8;
-
이 어휘 범위 내 에서 파일 핸들을 여는 것은 달리 언급하지 않는 한 스트림이 UTF-8로 인코딩된다고 가정하는 것입니다. 그렇게하면 다른 모듈이나 다른 프로그램의 코드에 영향을 미치지 않습니다.
use open qw( :encoding(UTF-8) :std );
-
를 통해 명명 된 문자를 활성화합니다
\N{CHARNAME}
.use charnames qw( :full :short );
-
DATA
핸들 이 있으면 명시 적으로 인코딩을 설정해야합니다. 이것을 UTF-8로하려면 다음과 같이 말합니다.binmode(DATA, ":encoding(UTF-8)");
물론 자신이 우려 할만한 다른 문제는 끝이 없지만, 이러한 용어에 대한 이해가 다소 약화 되더라도“모든 것이 UTF-8과 함께 작동하도록”하는 국가 목표를 근사화하는 것으로 충분합니다.
다른 pragma는 유니 코드와 관련이 없지만 다음과 같습니다.
use autodie;
강력히 추천합니다.
? ??? ? ?? ???? ??? ?? ???????? ? ??? ?
? ? ??????⸗????? ??? ???????⸗????? ???? ? ?
요즘 내 상용구는 다음과 같은 경향이 있습니다.
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 stack-dumped
# exceptions *unless* we're in an try block, in
# which case just cluck the stack dump instead
local $SIG{__WARN__} = sub {
if ($^S) { cluck "Trapped warning: @_" }
else { confess "Deadly warning: @_" }
};
while (<>) {
chomp;
$_ = NFD($_);
...
} continue {
say NFC($_);
}
__END__
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
“펄은 어떻게 든 [해야합니다 ! ] 기본적으로 유니 코드 사용”은 희귀하고 고립 된 경우에 미미하게 유용 할 정도로 충분히 말하기를 시작하지도 않습니다. 유니 코드는 단순히 더 큰 문자 레퍼토리 이상입니다. 또한 그 캐릭터들이 모두 여러 가지 방식으로 상호 작용하는 방식이기도합니다.
(일부) 사람들이 원하는 단순한 생각조차도 수백만 줄의 코드를 엄청나게 깨뜨릴 수 있다고 생각하는 것 같습니다.이 코드는 당신의 새롭고 멋진 Brave New World 현대성 을“업그레이드”할 기회가 없습니다 .
사람들이 척하는 것보다 훨씬 더 복잡합니다. 나는 지난 몇 년 동안 이것에 대해 거대하고 많은 것을 생각했습니다. 나는 내가 틀렸다는 것을 보여주고 싶다. 그러나 나는 생각하지 않습니다. 유니 코드는 기본적으로 적용하려는 모델보다 더 복잡하며, 카펫 아래에서 절대 쓸 수없는 복잡성이 있습니다. 당신이 시도하면, 당신은 당신의 자신의 코드 또는 다른 사람의 코드를 깰 것입니다. 어떤 시점에서, 당신은 단순히 유니 코드가 무엇인지 이해하고 배워야합니다. 그렇지 않은 척 할 수 없습니다.
? 내가 사용했던 것보다 훨씬 더 쉽게 유니 코드를 쉽게 만들 수 없습니다. 이것이 나쁘다고 생각되면 잠시 동안 다른 것을 시도하십시오. 그런 다음 ?으로 돌아 오십시오. 더 나은 세상으로 돌아 왔을 수도 있고, 그렇지 않으면 여러분과 같은 지식을 가져 와서 새로운 지식을 활용하여 이러한 것들을 더 잘 활용할 수 있습니다.
? ????? ??? ? ??????? ⸗ ????? ? ??????? ???? ?
최소한 “유니 코드를 기본적으로 활성화”하는 데 필요한 것으로 보이는 것은 다음과 같습니다.
-
모든 ? 소스 코드는 기본적으로 UTF-8이어야합니다.
use utf8
또는로 얻을 수 있습니다export PERL5OPTS=-Mutf8
. -
?
DATA
핸들은 UTF-8이어야합니다. 에서처럼 패키지 단위로이 작업을 수행해야합니다binmode(DATA, ":encoding(UTF-8)")
. -
? 스크립트에 대한 프로그램 인수는 기본적으로 UTF-8로 이해해야합니다.
export PERL_UNICODE=A
또는perl -CA
, 또는export PERL5OPTS=-CA
. -
표준 입력, 출력 및 오류 스트림의 기본값은 UTF-8입니다.
export PERL_UNICODE=S
그들 모두, 또는I
,O
및 / 또는E
그들 중 일부를 위해. 이것은 같습니다perl -CS
. -
달리 선언하지 않는 한 ?에 의해 열린 다른 핸들은 UTF-8로 간주해야합니다.
export PERL_UNICODE=D
이나와i
및o
이들의 특별한 사람을위한;export PERL5OPTS=-CD
작동 할 것이다. 그것은-CSAD
그들 모두를 만듭니다 . -
두 개의베이스와 모두 여는 스트림을 모두 덮으십시오
export PERL5OPTS=-Mopen=:utf8,:std
. 따옴표를 참조하십시오 . -
UTF-8 인코딩 오류를 놓치지 않으려 고합니다. 시도하십시오
export PERL5OPTS=-Mwarnings=FATAL,utf8
. 그리고 입력 스트림이 항상binmode
d:encoding(UTF-8)
뿐만 아니라 d 인지 확인하십시오:utf8
. -
128-255 사이의 코드 포인트는 ?로 이해되지 않은 이진 값뿐만 아니라 해당 유니 코드 코드 포인트로 이해해야합니다.
use feature "unicode_strings"
또는export PERL5OPTS=-Mfeature=unicode_strings
. 즉 것uc("\xDF") eq "SS"
하고"\xE9" =~ /\w/
. 간단export PERL5OPTS=-Mv5.12
하거나 좋을 수도 있습니다. -
명명 된 유니 코드 문자는 기본적으로 활성화되어 있지 않으므로 추가
export PERL5OPTS=-Mcharnames=:full,:short,latin,greek
하거나 일부를 추가하십시오 . uninames 및 tcgrep를 참조하십시오 . -
거의 항상 표준 모듈 에서 기능에 액세스해야 합니다
Unicode::Normalize
다양한 유형의 분해 .export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD
NFD를 통해 들어오는 물건과 NFC에서 나가는 물건을 항상 실행하십시오. 아직 알고있는 I / O 레이어는 없지만 nfc , nfd , nfkd 및 nfkc 참조하십시오 . -
에서 ? 문자열 비교를 사용하여
eq
,ne
,lc
,cmp
,sort
, C & CC & 항상 잘못입니다. 대신에@a = sort @b
, 당신은 필요합니다@a = Unicode::Collate->new->sort(@b)
. 뿐만 아니라에 추가 할 수 있습니다export PERL5OPTS=-MUnicode::Collate
. 이진 비교를 위해 키를 캐시 할 수 있습니다. -
Unicode 내장 은 유니 코드 데이터를 좋아
printf
하고write
잘못합니다. 당신은 사용해야합니다Unicode::GCString
전자의 경우Unicode::LineBreak
모듈 과 후자의 경우 모두 모듈 합니다 . uwc 및 unifmt를 참조하십시오 . -
당신이 그들을 정수로 계산 싶은 경우에, 당신은 당신의 실행해야 할 것
\d+
를 통해 캡처를 기능 ?가 내장되어 있기 때문에 atoi 함수 (3 것은) 현재 영리 충분하지 않습니다.Unicode::UCD::num
-
? 파일 시스템에서 파일 시스템 문제가 발생합니다. 일부 파일 시스템은 자동으로 NFC 로의 변환을 강제합니다. 다른 사람들은 자동으로 NFD 로의 전환을 강제합니다. 그리고 다른 사람들은 여전히 다른 일을합니다. 어떤 사람들은 그 문제를 완전히 무시하기 때문에 더 큰 문제를 야기합니다. 따라서 제자리를 유지하려면 고유 한 NFC / NFD 처리를 수행해야합니다.
-
귀하의 모든 ? 코드를 포함
a-z
하거나A-Z
그러한 MUST 변경할 수 를 포함하여m//
,s///
,와tr///
. 코드가 손상되었다는 비명을 지르는 붉은 깃발로 눈에 띄어 야합니다. 그러나 어떻게 바뀌어야하는지 명확하지 않습니다. 올바른 속성을 얻고 사례를 이해하는 것은 생각보다 어렵습니다. 나는 매일 unichars 와 uniprops를 사용 합니다. -
사용하는 코드
\p{Lu}
하는 코드만큼이나 잘못되었습니다[A-Za-z]
.\p{Upper}
대신 사용해야 하며 그 이유를 알아야합니다. 예,\p{Lowercase}
와\p{Lower}
다르다\p{Ll}
과\p{Lowercase_Letter}
. -
사용하는 코드
[a-zA-Z]
가 더 나쁩니다. 그리고 그것은 사용할 수 없습니다\pL
또는\p{Letter}
; 를 사용해야\p{Alphabetic}
합니다. 모든 알파벳이 글자가 아닌 것은 아닙니다! -
로 ? 변수를 찾고 있다면
/[\$\@\%]\w+/
문제가있는 것입니다. 을 찾아야/[\$\@\%]\p{IDS}\p{IDC}*/
하며 심지어 문장 부호 변수 또는 패키지 변수에 대해서는 생각하지 않습니다. -
공백을 확인하는 경우
\h
및 중에서 선택해야합니다.\v
. 그리고 당신은\s
그것을 의미 하지 않기 때문에[\h\v]
, 대중의 믿음과는 달리 , 절대 사용해서는 안됩니다 . -
당신이 사용하는 경우
\n
라인 경계를 위해, 또는\r\n
, 당신은 잘못하고 있습니다.\R
동일하지 않은를 사용해야 합니다! -
언제, 언제 전화를해야할지 모른다면 유니 코드 :: Stringprep를 언제 , 어디서 더 잘 배울 수 있습니다.
-
대소 문자를 구분하지 않는 비교는 분음 부호 등에 상관없이 두 글자가 같은 글자인지 확인해야합니다. 가장 쉬운 방법은 표준 Unicode :: Collate 모듈을 사용하는 것입니다.
Unicode::Collate->new(level => 1)->cmp($a, $b)
. 또한있다eq
방법과 같은, 당신은 아마도에 대해 배워야match
하고substr
도 방법. 이것들은 내장 된 것보다 뚜렷한 장점이 있습니다. -
때로는 충분하지 않아 대신 유니 코드 :: 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
로케일을 사용하지 않거나 영어를 사용하는 경우이지만 아이슬란드 어 로케일에서는 다릅니다. 이제 뭐? 힘든 일입니다. 당신은 함께 재생할 수 있습니다 ucsort 를 사용하여 이러한 것들 중 일부를 테스트. -
문자열 ” niño ” 에서 패턴 CVCV (자음, 모음, 자음, 모음)를 일치시키는 방법을 고려하십시오 . NFD 형식 (당신이 더 잘 알고 있음)은 그것을 “nin \ x {303} o”로 기억합니다. 이제 어떻게 할거야? 모음이
[aeiou]
잘못되었다고 가정(?=[aeiou])\X)
하더라도 (NWD에서도 ‘ø’와 같은 코드 포인트가 있기 때문에 어떤 것도 할 수 없습니다.) 는 분해되지 않기 없습니다 !) 그러나 방금 보여 드린 UCA 비교를 사용하여 ‘o’와 동일한 테스트를 수행합니다. NFD에 의존 할 수 없으며 UCA에 의존해야합니다.
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
그리고 그게 전부가 아닙니다. 사람들이 유니 코드에 대해 가정하는 백만 개의 가정이 있습니다. 그들이 이것을 이해하기 전까지는 be 코드가 깨질 것입니다.
-
인코딩을 지정하지 않고 텍스트 파일을 열 수 있다고 가정하는 코드가 손상되었습니다.
-
기본 인코딩이 일종의 기본 플랫폼 인코딩이라고 가정하는 코드가 손상되었습니다.
-
일본어 나 중국어의 웹 페이지가 UTF-8보다 UTF-16에서 더 적은 공간을 차지한다고 가정하는 코드는 잘못되었습니다.
-
Perl이 UTF-8을 내부적으로 사용한다고 가정하는 코드가 잘못되었습니다.
-
인코딩 오류가 항상 예외를 발생 시킨다고 가정하는 코드는 잘못되었습니다.
-
Perl 코드 포인트가 0x10_FFFF로 제한되었다고 가정하는 코드가 잘못되었습니다.
-
설정할 수 있다고 가정하는 코드
$/
유효한 행 구분 기호와 함께 작동 가 잘못되었습니다. -
같은 casefolding에 왕복 평등을 가정 코드
lc(uc($s)) eq $s
또는uc(lc($s)) eq $s
완전히 파괴 및 잘못된 것입니다.uc("σ")
과uc("ς")
둘 다 고려"Σ"
하지만lc("Σ")
아마도 그 모두를 반환 할 수 없습니다. -
모든 소문자 코드 포인트에 고유 한 대문자가 있다고 가정하거나 그 반대의 경우도 마찬가지입니다. 예를 들어
"ª"
대문자가없는 소문자입니다. 두 반면"ᵃ"
와은"ᴬ"
문자,하지만 그들은하지 소문자입니다; 그러나 해당 대문자 버전이없는 소문자 코드 포인트입니다. 알았어? 그들 모두 와 에도 불구하고 아닙니다 .\p{Lowercase_Letter}
\p{Letter}
\p{Lowercase}
-
대소 문자를 변경한다고 가정하는 코드는 문자열 길이가 변경되지 않는다고 가정합니다.
-
두 경우 만 있다고 가정하는 코드가 손상되었습니다. 타이틀 케이스도 있습니다.
-
문자 만 사용한다고 가정하는 코드가 손상되었습니다. 문자 외에도 숫자, 기호 및 마크에 대소 문자가 있음이 밝혀졌습니다. 실제로 사례를 변경하면
\p{Mark}
으로 전환하는 것과 같이 주요 일반 카테고리를 변경할 수도 있습니다\p{Letter}
. 또한 한 스크립트에서 다른 스크립트로 전환 할 수 있습니다. -
로캘에 종속되지 않는 경우를 가정하는 코드가 손상되었습니다.
-
POSIX 로캘에 대한 유니 코드를 제공한다고 가정하는 코드가 손상되었습니다.
-
기본 ASCII 문자를 얻기 위해 분음 부호를 제거 할 수 있다고 가정하는 코드는 사악하고, 여전히, 깨지거나, 뇌에 손상을 입거나, 잘못되며, 사형에 대한 정당성입니다.
-
분음 부호
\p{Diacritic}
와 표시\p{Mark}
가 같은 것으로 가정하는 코드 가 손상되었습니다. -
\p{GC=Dash_Punctuation}
커버 를 가정하는 코드\p{Dash}
나뉩니다. -
대시, 하이픈 및 마이너스를 가정하는 코드는 서로 동일하거나 각각 하나만 존재하며 잘못되었다고 가정합니다.
-
모든 코드 포인트가 하나 이상의 인쇄 열을 차지한다고 가정하는 코드가 깨졌습니다.
-
모든 것을 가정하는 코드
\p{Mark}
문자가 0 인쇄 열을 차지 가 깨졌습니다. -
닮았 문자가 있다고 가정 코드 입니다 비슷 가 손상되었습니다.
-
않는 문자가 있다고 가정 코드 하지 닮았가 없습니다 모두 나뉩니다.
-
하나의 행에서 코드 포인트 수에 제한이 있다고 가정하는 코드
\X
일치시킬 수 가 잘못되었습니다. -
가정
\X
할 수없는 코드 는\p{Mark}
문자로 가 잘못되었습니다. -
문자가
\X
아닌 두 개를 절대 보유 할 수 없다고 가정하는 코드\p{Mark}
가 잘못되었습니다. -
사용할 수 없다고 가정하는 코드
"\x{FFFF}"
가 잘못되었습니다. -
두 개의 UTF-16 (서로 게이트) 코드 단위가 필요한 BMP 이외의 코드 포인트를 가정하는 코드는 코드 단위당 하나씩 두 개의 개별 UTF-8 문자로 인코딩됩니다. 그렇지 않습니다 : 단일 코드 포인트로 인코딩합니다.
-
결과 BOM을 UTF-8의 시작 부분에 넣으면 BOM이있는 UTF-16 또는 UTF-3에서 UTF-8로 코드 변환되는 코드가 손상됩니다. 엔지니어가 눈꺼풀을 제거해야하는 것은 너무 어리 석습니다.
-
CESU-8이 유효한 UTF 인코딩이라고 가정하는 코드가 잘못되었습니다. 마찬가지로 U + 0000 인코딩을 다음과 같이 생각하는 코드
"\xC0\x80"
UTF-8 는 깨져서 잘못되었습니다. 이 사람들은 또한 눈꺼풀 치료를받을 자격이 있습니다. -
문자가
>
항상 오른쪽을<
가리키고 항상 왼쪽을 가리키는 것으로 가정하는 코드 는 잘못되었습니다. 실제로는 그렇지 않기 때문입니다. -
먼저 문자를 출력
X
한 다음 문자를 출력하면 잘못된Y
것으로 표시 되는 것으로 가정하는 코드입니다XY
. 때로는 그렇지 않습니다. -
ASCII가 영어를 올바르게 작성하기에 충분하다고 가정하는 코드는 어리 석고 근시안적이며 문맹이며 깨지거나 악하고 잘못입니다. 그들의 머리와 떨어져! 그것이 너무 극단적 인 것처럼 보인다면, 우리는 타협 할 수 있습니다. (나머지는 덕트 테이프가됩니다.)
-
모든
\p{Math}
코드 포인트가 보이는 문자 라고 가정하는 코드가 잘못되었습니다. -
\w
문자, 숫자 및 밑줄 만 포함 한다고 가정하는 코드 가 잘못되었습니다. -
가정합니다 코드
^
및~
문장 부호있는이 잘못되었습니다. -
ü
움라우트가 있다고 가정하는 코드 가 잘못되었습니다. -
₨
문자가 포함되어 있다고 믿는 코드 는 잘못되었습니다. -
믿는 코드 는 크게 파괴 된
\p{InLatin}
것과 동일\p{Latin}
합니다. -
\p{InLatin}
거의 항상 유용 하다고 생각되는 코드 는 거의 틀림 없습니다. -
$FIRST_LETTER
어떤 알파벳의 첫 번째 문자와 같은 알파벳$LAST_LETTER
의 마지막 문자로 주어진 것으로 , 그것은[${FIRST_LETTER}-${LAST_LETTER}]
거의 모든 것이 거의 항상 깨지고 잘못되고 의미가 없다는 것을 믿는 코드 . -
누군가의 이름에 특정 문자 만 포함 할 수 있다고 믿는 코드는 어리 석고 공격적이며 잘못되었습니다.
-
유니 코드를 ASCII로 줄이려는 코드는 단순히 잘못된 것이 아니라 가해자가 다시 프로그래밍 작업을 할 수 없도록해야합니다. 기간. 나는 그들이 지금까지 많은 것을 잘하지 않았기 때문에 그들이 다시 볼 수 있도록해야한다고 긍정적이지 않습니다.
-
텍스트 파일 인코딩이 존재하지 않는 척하는 방법이 있다고 생각되는 코드는 손상되어 위험합니다. 상대방의 눈을 찌를 수도 있습니다.
-
알 수없는 문자를 변환하는 코드
?
는 깨지거나 어리 석고 뇌가 치며 표준 권장 사항에 위배됩니다 . 왜 RTFM입니까? -
표시되지 않은 텍스트 파일의 인코딩이 Zeus의 번개 만 고칠 수있는 치명적인 후부와 naïveté의 죄책감이 있다고 추측 할 수있는 코드.
-
?
printf
너비를 사용 하여 유니 코드 데이터를 채우고 정당화 할 수 있다고 생각 하는 코드가 손상되었습니다. -
주어진 이름으로 파일을 성공적으로 생성 한 후에 실행
ls
하거나readdir
주변 디렉토리에서 파일을 생성하면 실제로 생성 한 이름을 가진 파일이 버그, 고장 및 잘못임을 알게되는 코드입니다. 이것에 놀라지 마라! -
UTF-16이 고정 너비 인코딩이라고 믿는 코드는 어리 석고 깨지고 잘못되었습니다. 프로그래밍 라이센스를 취소하십시오.
-
한 평면의 코드 포인트를 다른 평면의 코드 포인트와 다르게 처리하는 코드는 사실상 깨져서 잘못되었습니다. 학교로 돌아가십시오.
-
같은 것들만이
/s/i
일치"S"
하거나"s"
깨지거나 잘못 되었다고 믿는 코드 . 당신은 놀랄 것입니다. -
사용
\PM\pM*
하는 대신 grapheme 클러스터를 찾는 데 사용 되는 코드가\X
잘못되었습니다. -
ASCII 세계로 돌아 가고자하는 사람들은 진심으로 그렇게하도록 격려해야하며, 영광스러운 업그레이드를 기리기 위해 모든 데이터 입력 요구에 대해 사전 전기 수동 타자기를 무료 로 제공 해야합니다. 그들에게 보낸 메시지는 한 줄에 40 자씩 ᴀʟʟᴄᴀᴘs 전신을 통해 보내야하며 택배사가 직접 배달해야합니다. 중지.
? ? ? ? ? ? ? ? ?
필자가 작성한 것보다 얼마나 많은 “기본 유니 코드 ?”를 얻을 수 있는지 모르겠습니다. 음, 그래 내가 할 : 사용되어야 Unicode::Collate
하고Unicode::LineBreak
, 너무. 그리고 아마도 더.
보시다시피, 너무 많은 유니 코드 일들이 당신이 정말 거기 않는 거기에 대해 걱정할 필요가 이제까지 “유니 코드로 기본”으로 그러한 일을 존재는.
우리가 back 5.8에서했던 것처럼, 처음부터 올바르게 설계되지 않은 코드에이 모든 것을 적용하는 것은 불가능하다는 것을 발견 할 것입니다. 당신의 선의의 이기심은 전 세계를 돌파했습니다.
그리고 한 번만해도 여전히 많은 문제를 해결해야하는 중요한 문제가 있습니다. 뒤집을 수있는 스위치가 없습니다. 뇌 외에는 아무것도 없으며 진짜 뇌를 의미 합니다 만으로는 충분 . 당신이 배워야 할 것들이 많이 있습니다. 수동 타자기 후퇴 모듈로, 당신은 단순히 무지에 몰래 숨길 수 없습니다. 이것은 21 세기이며, 당신은 고의적 인 무지로 유니 코드를 원치 않을 수 없습니다.
당신은 그것을 배워야합니다. 기간. “모든 것이 제대로 작동하는”것은 결코 쉬운 일 이 아닙니다. 왜냐하면 많은 것들이 작동 작동 입니다. “모든 것이 작동하게하는”방법이있을 수 있다는 가정은 무효가됩니다.
매우 적은 수의 매우 제한된 작업에 대해 몇 가지 합리적인 기본값을 얻을 수 있지만 생각보다 훨씬 많은 것을 생각하지는 않습니다.
하나의 예로서, 정식 순서는 실제 두통을 유발할 것입니다. ? "\x{F5}"
‘õ’ , "o\x{303}"
‘õ’ , "o\x{303}\x{304}"
‘ȭ’ , "o\x{304}\x{303}"
‘ō̃’ 은 모두 ‘õ’ 와 일치해야 하지만 어떻게 세상에서 그렇게 하시겠습니까? 이것은 보이는 것보다 어렵지만 고려해야 할 사항입니다. ?
나는 펄에 대해 알고 한 가지 있다면, 그것은 유니 코드 비트 및하지 않는다 할 것입니다,이 일이 내가 당신을 약속한다 : “ᴛʜᴇʀᴇ ɪs ɴᴏ Uɴɪᴄᴏᴅᴇ ᴍᴀɢɪᴄ ʙᴜʟʟᴇᴛ” ?
일부 기본값을 변경하고 원활한 항해를 할 수는 없습니다. 내가로 PERL_UNICODE
설정하여 ?을 실행하는 것은 사실 "SA"
이지만, 그게 전부이며 심지어 대부분 명령 줄에 대한 것입니다. 실제 작업을 위해서는 위에서 설명한 여러 단계를 모두 거쳐야합니다.
? ¡ ƨdləɥ ƨᴉɥʇ ədoɥ puɐ ʻλɐp əɔᴉu ɐ əʌɐɥ ʞʞnlnl poo⅁ ?
답변
유니 코드 텍스트 처리에는 두 단계가 있습니다. 첫 번째는 “정보를 잃지 않고 어떻게 입력하고 출력 할 수 있는가”입니다. 두 번째는 “지역 언어 규칙에 따라 텍스트를 처리하는 방법”입니다.
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으로 인코딩 된 파일에서 작동한다는 의미는 아닙니다. 이제 안전을 유지하고 사용자 데이터를 낭비하는 두통을 피하십시오!
유니 코드 처리의 쉬운 부분은 인코딩 출력 및 디코딩 입력입니다. 어려운 부분은 모든 입력 및 출력을 찾고 어떤 인코딩인지 결정하는 것입니다. 그러나 이것이 큰 돈을 얻는 이유입니다. 🙂
답변
우리 모두는 여러 가지 이유로 어려운 문제라는 데 동의하지만, 모든 사람이 더 쉽게 만들려고 노력하는 이유입니다.
CPAN에는 utf8 :: all 모듈이 있으며 “유니 코드를 켜십시오. 모든 모듈 “을 시도합니다.
지적한 바와 같이, 전체 시스템 (외부 프로그램, 외부 웹 요청 등)이 유니 코드를 사용하도록 마술처럼 만들 수는 없지만 공통된 문제를 쉽게 수행 할 수있는 합리적인 도구를 만들기 위해 협력 할 수 있습니다. 이것이 우리가 프로그래머 인 이유입니다.
만약 utf8 :: all이 당신이 생각하는 것을하지 않는다면, 그것을 향상시키기 위해 그것을 향상 시키자. 또는 사람들의 다양한 요구에 맞게 가능한 추가 도구를 만들어 봅시다.
`
답변
유니 코드와 Perl과의 관계를 오해한다고 생각합니다. 데이터, 유니 코드, ISO-8859-1 또는 기타 여러 가지 를 저장하는 방법에 관계없이 프로그램은 입력으로 얻는 바이트를 해석하는 방법 (디코딩)과 출력하려는 정보를 표현하는 방법 (인코딩)을 알아야합니다 ). 그 해석을 잘못하면 데이터가 왜곡됩니다. 프로그램 내부에는 프로그램 외부의 작업을 수행하는 방법을 알려주는 마법의 기본 설정이 없습니다.
ASCII가되는 모든 것에 익숙하기 때문에 어렵다고 생각합니다. 당신이 생각해야 할 모든 것은 프로그래밍 언어와 상호 작용 해야하는 모든 것들에 의해 무시되었습니다. 모든 것이 UTF-8 만 사용하고 선택의 여지가 없다면 UTF-8도 쉽습니다. 그러나 모든 것이 UTF-8을 사용하는 것은 아닙니다. 예를 들어 입력 핸들이 실제로 UTF-8 옥텟을 얻는다고 생각하지 않기를 원하며, 읽은 것이 UTF-8을 처리 할 수 있다면 출력 핸들이 UTF-8이되는 것을 원하지 않습니다 . 펄은 그런 것들을 알 방법이 없습니다. 그래서 당신은 프로그래머입니다.
Perl 5의 유니 코드가 너무 복잡하다고 생각하지 않습니다. 나는 그것이 무섭고 사람들은 그것을 피한다고 생각합니다. 차이가 있습니다. 이를 위해 Learning Perl, 6th Edition 에는 유니 코드를 넣었 으며 효과적인 Perl Programming 에는 많은 유니 코드 항목이 있습니다. 유니 코드와 그 작동 방식을 배우고 이해하는 데 시간을 투자해야합니다. 그렇지 않으면 효과적으로 사용할 수 없습니다.
답변
이 글을 읽는 동안 사람들이 ” UTF-8 “을 ” Unicode ” 와 동의어로 사용하고 있다는 인상을 종종받습니다 . ASCII 코드와 비교하여 확대 된 유니 코드의 “코드 포인트”와 유니 코드의 다양한 “인코딩”을 구분하십시오. UTF-8, UTF-16 및 UTF-32 는 현재 버전이고 일부는 더 이상 사용되지 않습니다.
UTF-8 ( 및 다른 모든 인코딩 )이 존재하며 입력 또는 출력에서만 의미가 있습니다. 내부적으로 Perl 5.8.1부터 모든 문자열은 유니 코드 “코드 포인트”로 유지됩니다. 사실, 이전에 감탄했던 일부 기능을 활성화해야합니다.
답변
야생에는 정말 무서운 양의 고대 코드가 있으며, 그 대부분은 일반적인 CPAN 모듈 형태입니다. 영향을받을 수있는 외부 모듈을 사용하는 경우 유니 코드를 활성화하는 데 매우 신중해야하며 정기적으로 사용하는 여러 Perl 스크립트에서 유니 코드 관련 오류를 식별하고 수정하려고합니다 (특히 iTiVo 실패) 트랜스 코딩 문제로 인해 7 비트 ASCII가 아닌 것은 잘못되었습니다.)
답변
유니 코드 문자열 기능을 활성화해야하며 v5.14를 사용하는 경우 이것이 기본값입니다.
유니 코드 식별자 esp를 실제로 사용해서는 안됩니다. perl5에서 안전하지 않은 utf8을 통한 외래 코드의 경우 cperl만이 권리를 얻었습니다. 예를 들어 http://perl11.org/blog/unicode-identifiers.html 참조
파일 핸들 / 스트림에 대한 utf8 관련 : 외부 데이터의 인코딩을 스스로 결정해야합니다. 라이브러리는이를 알 수 없으며 libc조차도 utf8을 지원하지 않기 때문에 적절한 utf8 데이터는 거의 없습니다. utf8의 창 수차 인 wtf8이 더 있습니다.
BTW : 무스는 실제로 “Modern Perl”이 아니며, 단지 이름을 빼앗 았습니다. Moose는 Bjarne Stroustrup 스타일과 혼합 된 완벽한 Larry Wall 스타일 포스트 모더니즘 펄입니다. 적절한 구현. cperl과 perl6은 진정한 현대식 perl이며, 형식이 기능을 따르고 구현이 감소되고 최적화됩니다.