perl-将utf8字节修剪为';长度';并清理数据

perl-将utf8字节修剪为';长度';并清理数据,perl,utf-8,Perl,Utf 8,我有utf8的字节序列,需要把它修剪到30字节。这可能导致最后的顺序不完整。我需要弄清楚如何删除不完整的序列 e、 g 首先,请不要使用字节(不要假设Perl中的任何内部编码)。正如文档所说:这个pragma反映了早期将Unicode合并到perl中的尝试,并且已经被取代。强烈建议不要将此模块用于调试目的以外的任何用途 若要在行尾去除不完整的序列,假设它包含八位字节,请使用Encode::decode的Encode::FB_QUIET处理模式,在命中无效序列后停止处理,然后将结果重新编码: my

我有utf8的字节序列,需要把它修剪到30字节。这可能导致最后的顺序不完整。我需要弄清楚如何删除不完整的序列

e、 g


首先,请不要使用
字节
(不要假设Perl中的任何内部编码)。正如文档所说:这个pragma反映了早期将Unicode合并到perl中的尝试,并且已经被取代。强烈建议不要将此模块用于调试目的以外的任何用途

若要在行尾去除不完整的序列,假设它包含八位字节,请使用
Encode::decode
Encode::FB_QUIET
处理模式,在命中无效序列后停止处理,然后将结果重新编码:

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

请注意,如果您计划在将来将其用于另一种编码,则并非所有编码都支持此处理方法。

UTF-8具有一些简洁的属性,允许我们在处理UTF-8而不是字符时执行您想要的操作。所以首先,你需要UTF-8

use Encode qw( encode_utf8 );
my $bytes = encode_utf8($str);
现在,在代码点之间进行拆分。每个代码点的UTF-8编码将从字节匹配<代码> 0B0XXXXXX或<代码> 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"

很好,是吗?不。上面可以截断字形的中间部分。图位(特别是“扩展图位簇”)是人们将其视为单个视觉单元的东西。例如,“é”是一个图形,但可以使用两个代码点(
“\x{0065}\x{0301}”
)对其进行编码。如果在两个代码点之间切换,它将是有效的UTF-8,但“é”将变成“e”!如果这是不可接受的,上述解决方案也是不可接受的。(奥列格的解决方案也面临同样的问题。)

不幸的是,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"
my$max_bytes=6;
my$str=“abcd\x{0065}\x{0301}fg”;#abcdéfg
我的$bytes='';
my$bytes\u left=$max\u字节;
而($str=~/(\X)/g){
my$grapheme=$1;
my$grapheme\u bytes=encode\u utf8($grapheme);
$bytes\u left-=长度($grapheme\u字节);
如果剩余$bytes_<0,则为最后一个;
$bytes.=$grapheme\u字节;
}
#$bytes包含encode_utf8(“abcd”)
#而不是编码_utf8(“abcde”)
#或编码_utf8(“abcde”)。“\xCC”

太棒了!!谢谢如果我确定$b是utf8编码的,那么“使用字节”是否安全。否。没有人保证Perl在内部总是使用UTF-8。使用
Encode::Encode('utf8',…)
(或
Encode::Encode\u utf8
)。否。使用
encode
总是安全的,所以,即使此时此刻你知道它是正确的,你为什么还要在一半的时间里使用其他错误的东西呢。
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"