0

Perl を使用して、各レコードが ASCII または Unicode 文字で構成される固定レコードを持つファイルを作成して、そのファイルをランダム アクセス ファイルとして評価できるようにしたいと考えています。

レコードには、最大文字数がそれぞれ 100、60、40 の 3 つの文字列 str1、str2、および str3 があり、文字列には ASCII または UTF-8 文字を含めることができます。

以下のように perl の pack/unpack 関数を使用していますが、期待した結果が得られませんでした。

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;

(どちらの場合も、aNUL を使用してパックする場合とA、スペースを使用してパックする場合に使用します。)

于 2013-04-19T18:08:22.330 に答える
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 に答える
0

パック テンプレートの解釈は正確ではありません。aバイト文字列のテンプレートが必要です。文字列からバイトを取得するには、文字列もエンコードする必要があります。

次のスクリプトは、2 つのレコードを作成し、2 番目のレコードを読み取ります。文字列は指定されたサイズで切り捨てられます。つまり、マルチバイト文字の途中である可能性があります。

#!/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 に答える