2012-06-08 4 views
3

나는 utf8 바이트 시퀀스를 가지고 있으며 30 바이트라고 말하기 위해 그것을 자른다. 결국 불완전한 시퀀스가 ​​발생할 수 있습니다. 불완전한 순서를 제거하는 방법을 알아야합니다.perl- utf8 바이트를 '길이'로 자르고 데이터를 살균 처리하십시오.

예컨대

$b="\x{263a}\x{263b}\x{263c}"; 
my $sstr; 

print STDERR "length in utf8 bytes =" . length(Encode::encode_utf8($b)) . "\n"; 
{ 
use bytes; 
$sstr= substr($b,0,29); 
} 

#After this $sstr contains "\342\230\272\342"\0 
# How to remove \342 from the end 

답변

3

첫째, bytes를 사용하지 (펄의 내부 인코딩한다고 가정하지) 마십시오. 설명서에 다음과 같이 쓰여 있습니다.이 pragma는 유니 코드를 perl에 통합하려는 초기 시도를 반영한 ​​것이므로 < ...>이 모듈을 디버깅 용도 이외의 용도로 사용하지 않는 것이 좋습니다.

, 그것은 옥텟이 포함되어 가정, 라인의 끝에서 불완전한 순서를 제거 당신이 잘못된 순서를 공격하고 그냥 결과를 인코딩하면 처리를 중지 Encode::decodeEncode::FB_QUIET 처리 모드를 사용하려면 다음의 경우 그

my $valid = Encode::decode('utf8', $sstr, Encode::FB_QUIET); 
$sstr = Encode::encode('utf8', $valid); 

주 앞으로 다른 인코딩과 함께 사용하려고 계획하고 있지만, 모든 인코딩이이 처리 방법을 지원하지는 않습니다.

+0

위대한 !! 감사 . $ b가 utf8로 인코딩되어있을 때 "바이트 사용"이 안전하지 않습니까? – user1444975

+0

아니요. 내부적으로 Perl이 항상 UTF-8을 사용한다는 것을 아무도 보장하지 않습니다. 'Encode :: encode ('utf8', ...)'(또는'Encode :: encode_utf8')를 사용하십시오. –

+0

아니요. 항상 'encode'를 사용하는 것이 안전합니다. 그렇다면 지금 바로이 순간에 알겠지만 왜 시간의 절반이 아닌 다른 것을 사용하고 싶습니까? – ikegami

6

UTF-8에는 문자가 아닌 UTF-8을 처리하면서 원하는 것을 수행 할 수있는 몇 가지 깔끔한 속성이 있습니다. 먼저 UTF-8이 필요합니다.

use Encode qw(encode_utf8); 
my $bytes = encode_utf8($str); 

이제 코드 포인트 간을 나눕니다. 모든 코드 포인트의 UTF-8 인코딩은 0b0xxxxxxx 또는 0b11xxxxxx과 일치하는 바이트로 시작하며 코드 포인트의 중간에서 해당 바이트를 찾지 않습니다. 즉, 당신이 함께

[\x00-\x7F\xC0-\xFF] 

전에 잘라내는 것을 의미합니다, 우리가 얻을 :

use Encode qw(encode_utf8); 

my $max_bytes = 8; 
my $str = "\x{263a}\x{263b}\x{263c}"; # ☺☻☼ 

my $bytes = encode_utf8($str); 
$bytes =~ s/^.{0,$max_bytes}(?![^\x00-\x7F\xC0-\xFF])\K.*//s; 

# $bytes contains encode_utf8("\x{263a}\x{263b}") 
#  instead of encode_utf8("\x{263a}\x{263b}") . "\xE2\x98" 

그레이트, 그래? 아니. 위의 내용은 한 문장의 중간 부분에서 잘릴 수 있습니다. grapheme (구체적으로, "extended grapheme cluster")은 누군가가 하나의 시각적 단위로 인식하는 것입니다. 예를 들어 "é"는 문자이지만 2 코드 포인트 ("\x{0065}\x{0301}")를 사용하여 인코딩 할 수 있습니다. 두 코드 포인트 사이를 자르면 UTF-8이 유효하지만 "é"는 "e"가됩니다! 수용 할 수 없다면 위의 해결책도 아닙니다. (Oleg의 해결책도 마찬가지입니다.)

유감스럽게도 UTF-8의 속성은 더 이상 여기서 도움이되지 않습니다. 우리는 한 번에 하나의 grapheme을 붙잡고 우리가 하나가 될 수 없을 때까지 출력물에 그것을 더할 필요가 있습니다.

my $max_bytes = 6; 
my $str = "abcd\x{0065}\x{0301}fg"; # abcdéfg 

my $bytes = ''; 
my $bytes_left = $max_bytes; 
while ($str =~ /(\X)/g) { 
    my $grapheme = $1; 
    my $grapheme_bytes = encode_utf8($grapheme); 
    $bytes_left -= length($grapheme_bytes); 
    last if $bytes_left < 0; 
    $bytes .= $grapheme_bytes; 
} 

# $bytes contains encode_utf8("abcd") 
#  instead of encode_utf8("abcde") 
#    or encode_utf8("abcde") . "\xCC" 
관련 문제