EBCDIC转换的设计方法

时间:2017-04-08 13:07:16

标签: perl ebcdic

我有一个包含以下内容的格式文件

FIELD NO.,FIELD NAME,STARTING POSITION,ENDING POSITION,LENGTH,INDICATOR
1,SEQ_NO,1,11,11,N
2,CTR_REC_ID,12,14,3,N
3,CTR_SEQ_AMT,15,23,9,A
4,CTR_CONTRACT_NO,24,46,23,N
5,CTR_CONTRACT_AMT,47,59,13,A
6,CTR_TRACK_NO,60,62,3,N

该文件提供了有关每个字段的起始位置,结束位置和长度的详细信息。

我的脚本读取格式文件并将内容存储到数组中。然后逐行读取源文件,当格式文件中的指示符 A 时,将EBCDIC字符转换为合适的ASCII字符。

这是一个示例源文件,其索引显示了格式文件中列出的字符位置和字段。它不是数据文件的一部分。

         1         2         3         4         5         6         7
1234567890123456789012345678901234567890123456789012345678901234567890
[         ][ ][       ][                     ][           ][ ]
         5|CTR00002173{09C00000000001         000000000201AE00      
        22|CTR00002243A52C00000000007         000000002358JF00
        24|CTR00008456J52C00000000008         000000002465{F00

根据格式文件,第一行的CTR_SEQ_AMT值为00002173{{必须转换为0并用空格替换前导零,并将其设为十进制值(十进制(9,2))。

最终输出将如下所示:

     5|CTR    217.3009C00000000001                  20.11E00
    22|CTR    224.3152C00000000007                -235.85F00
    24|CTR   -845.6552C00000000008                 246.50F00
  

{ - > 0,A - > 1,J - > 5(将十进制值转换为负数)。

我使用Perl得到了上面的输出,但我的脚本性能不好。

我的源文件可以有一百万条记录。根据我的脚本,我有2个循环:一个用于读取格式文件并将数据存储到一个数组中,另一个用于逐行读取源文件并进行转换。因此,如果格式文件有10个要转换的字段,我的代码将遍历这些百万行10次。

不是有两个循环,我可以使用单个循环来读取格式文件,当字段的指示符为A时,对于特定字段,一次在所有行中执行以下操作:

  • 将前导零替换为空白
  • 将EBCDIC字符转换为ASCII字符
  • 将其设为小数值。

目前我的代码有以下行来执行上述3个步骤。这一行包含源文件中的每一行。

$f_cnt   = $start_pos - 1;
$dec_cnt = $array_length[$cnt] - 2;
$field   = substr("$line",  $end_pos -1, 1);

if ( $field  eq '{' ) {
     print "replacing { \n";
     $x = substr($line, $f_cnt, $dec_cnt);
     $x =~ s/^(0*)/' ' x length($1)/e;
     substr($line, $f_cnt, $dec_cnt, "$x.");
     substr($line, $end_pos, 1, "0") ;
 }

1 个答案:

答案 0 :(得分:0)

经过一些优化后,我有:

resolve: {
    extensions: ['.ts', '.js'],
    modules: [path.resolve(__dirname, "src"), "node_modules"]
},

可悲的是,我所取得的最快成就是:

my %ebcdic_fields;

while (my $line = <DATA>) {
    my (undef, undef, $start, undef, $length, $indicator) = split /,/, $line;
    next if $indicator !~ m/^A/;
    $ebcdic_fields{$start-1} = $length - 2;
}

while (my $line = <>) {
    while (my ($start, $length) = each %ebcdic_fields) {
        my $fpos = $start + $length + 1;
        my $before = substr ($line, $start, $length);
        my $format = substr ($line, $fpos, 1);
        my $trimed_before = $before + 0; # keep at least one 0 before the dot
        if ($format ge 'J' and $format ne '{') {
            substr ($line, $fpos, 1) =~ tr/}JKLMNOPQR/0123456789/;
            substr ($line, $start, $length) = ' ' x ($length - length($trimed_before) - 2) . '-' . $trimed_before . '.';
        } else {
            substr ($line, $fpos, 1) =~ tr/{ABCDEFGHI/0123456789/;
            substr ($line, $start, $length) = ' ' x ($length - length($trimed_before) - 1) . $trimed_before . '.';
        }
    }
    print $line;
}
__DATA__
1,SEQ_NO,1,11,11,N
2,CTR_REC_ID,12,14,3,N
3,CTR_SEQ_AMT,15,23,9,A
4,CTR_CONTRACT_NO,24,46,23,N
5,CTR_CONTRACT_AMT,47,59,13,A
6,CTR_TRACK_NO,60,62,3,N