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"
위대한 !! 감사 . $ b가 utf8로 인코딩되어있을 때 "바이트 사용"이 안전하지 않습니까? – user1444975
아니요. 내부적으로 Perl이 항상 UTF-8을 사용한다는 것을 아무도 보장하지 않습니다. 'Encode :: encode ('utf8', ...)'(또는'Encode :: encode_utf8')를 사용하십시오. –
아니요. 항상 'encode'를 사용하는 것이 안전합니다. 그렇다면 지금 바로이 순간에 알겠지만 왜 시간의 절반이 아닌 다른 것을 사용하고 싶습니까? – ikegami