【问题标题】:Perl: How to avoid regex UTF-8 errors when reading from middle of filePerl:从文件中间读取时如何避免正则表达式 UTF-8 错误
【发布时间】:2016-02-02 04:42:58
【问题描述】:

在寻找 open(FILE, '<:utf8', $file) or die; seek(FILE, $readFrom, 0); read(FILE, $_, $size); 之后读取 utf8 编码文件有时会“分解”一个 unicode 字符,因此读取字符串的开头不是有效的 UTF-8。

如果你这样做,例如s{^([^\n]*\r?\n)}{}i 去除不完整的第一行,您会收到“格式错误的 UTF-8 字符(致命)”错误。

如何解决这个问题?

How do I sanitize invalid UTF-8 in Perl? 中列出的一种解决方案是删除所有无效的 UTF-8 字符:

tr[\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}][]cd;

但是,搜索整个字符串似乎有点过头了,因为只有读取字符串中的第一个字节可以被破坏。

任何人都可以建议一种方法来仅去除初始的无效字符(或使上述替换不会在格式错误的 UTF-8 上消失)吗?

【问题讨论】:

  • 仅将tr 应用于第一个字符?
  • 这不应该发生,请参阅perldoc -f read 注意字符: ...默认情况下,所有文件句柄都在字节上操作,但是...如果文件句柄已使用 " :utf8" I/O 层 I/O 将在 UTF-8 编码的 Unicode 字符上运行,而不是字节请给出一个最小的例子
  • tr 去掉了至少 29 个有效字符!!!

标签: regex perl utf-8


【解决方案1】:

将流读取为字节,在开始时去除部分字符,确定最后一个完整字符的结束位置,然后解码剩下的内容。

use Encode qw( STOP_AT_PARTIAL );
use Fcntl  qw( SEEK_TO );

my $encoding = Encode::find_encoding('UTF-8');

open(my $FILE, '<:raw', $file) or die $!;
seek($FILE, $readFrom, SEEK_TO) or die $!;
my $bytes_read = read($FILE, my $buf, $size);
defined($bytes_read) or die $!;

$buf =~ s/^[\x80-\xBF]+//;

my $str = $encoding->decode($buf, STOP_AT_PARTIAL);

如果您想阅读更多内容,请使用 read 的 4-arg 形式,此时不要在开头跳过任何内容。

my $bytes_read = read($FILE, $buf, $size, length($buf));
defined($bytes_read) or die $!;

$str .= $encoding->decode($buf, STOP_AT_PARTIAL);

相关阅读:Convert UTF-8 byte stream to Unicode

【讨论】:

  • s/^\x80+//?这不是 UTF-8 的工作方式。可以使用s/^[\x80-\xBF]+// 剥离连续字节。
  • @nwellnhof,确认!当然! (我知道这一点,正如我对链接问题的回答所证明的那样。)已修复。
猜你喜欢
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-11
  • 2014-02-01
  • 1970-01-01
相关资源
最近更新 更多