0

我想使用 perl 创建一个具有固定记录的文件,其中每个记录可能由 ASCII 或 Unicode 字符组成,以便我可以将该文件评估为随机访问文件。

在记录中,我有三个字符串 str1、str2 和 str3,最大字符数分别为 100、60、40,任何字符串都可能包含 ASCII 或 UTF-8 字符。

我正在使用下面的 perl 打包/解包功能,但无法获得预期的结果。

open (FILE,">>:utf8",filename) or die "can't open\n";
$record=pack("U100 U60 U40",$str1,$str2,$str3);
print FILE $record;

读这个

open (FILE,"<:utf8",filename) or die "can't open\n";
seek(FILE,$buffer,200);
@data=unpack("U100 U60 U40",$buffer);
print @data;

请帮助我如何做到这一点。

4

3 回答 3

1

首先,US-ASCII 是 UTF-8 的子集,因此“ASCII 或 UTF-8”与“UTF-8”相同。

其次,“字符”是字符串的一个元素。它们不是一种存储格式,也没有特定的大小,因此字段长度不能以字符来衡量。这些字段可以以字节Unicode 代码点或许多其他单位来衡量,但不能以字符为单位。

如果字段长度以字节为单位,则所需的填充量会根据编码文本的大小而有所不同,因此您需要在打包之前进行编码。

use Encode qw( encode_utf8 );

open(my $fh, '>>:raw',  $filename)
   or die("Can't open $filename: $!\n");

my $record = pack 'a100 a60 a40', map encode_utf8($_), $str1, $str2, $str3;
print $fh $record;

如果在 Unicode 代码点中测量字段长度的可能性很小,则需要在打包后进行编码。

open(my $fh, '>>:utf8',  $filename)
   or die("Can't open $filename: $!\n");

my $record = pack 'a100 a60 a40', $str1, $str2, $str3;
print $fh $record;

(在这两种情况下,都使用aNULA打包,以及空格打包。)

于 2013-04-19T18:08:22.330 回答
0

您对包模板的解释并不准确。您需要a字节字符串的模板。您还必须对字符串进行编码才能从中获取字节。

以下脚本创建两条记录并读回第二条记录。字符串在给定大小处被截断,即可能在多字节字符的中间。

#!/usr/bin/perl
use warnings;
use strict;
use feature qw(say);

use Encode;

my $filename = 'utf.txt';
my @sizes    = (8, 4, 2);
my $mask     = join ' ', map "a$_", @sizes;
my $sum      = 0;
$sum        += $_ for @sizes;


sub record {
    return map shift(@_) x ($_ + 10), @sizes;
}


sub output {
    open my $FILE, '>>', $filename or die "Can't open $filename: $!";
    my $record = pack $mask, map { Encode::encode('utf8', $_) } record(@_);
    print $FILE $record;
    close $FILE;
}


sub input {
    my $n = shift;
    open my $FILE, '<', $filename or die "Can't open $filename: $!\n";
    warn  $sum * ($n - 1);
    seek $FILE, $sum * ($n - 1), 0;
    read $FILE, my ($buffer), $sum;
    my @items = unpack $mask, $buffer;
    say for @items;
}


use utf8;
output(qw/ø ¶ đ/);
output(qw/Č á ∀/);
input(2);
于 2013-04-19T12:19:30.967 回答
0

Parse:: FixedLength

模块对此非常有用,这样的内容应该有助于解释:

use Parse::FixedLength;
my $parser = Parse::FixedLength->new([
    str1    =>  100,
    str2    =>  60,
    str3    =>  40,
]);  
open (FILE,"<:utf8",filename) or die "can't open\n";
while (my $line = <FILE>) {
  my %vals = ('str1' => $str1,
              'str2' => $str2,
              'str3' => $str3,
             );
  print = $parser->pack(\%vals);
}
close FILE;
于 2013-04-19T11:24:40.277 回答