基于输入文件的 PERL 固定宽度到 CSV
PERL Fixed Width to CSV based on Input Files
已编辑:我正在尝试创建一个简短的脚本,该脚本需要一个输入固定宽度文件和一个具有每个属性的起始位置和长度的文件,然后将文件输出为 CSV 而不是固定宽度。我还没有搞砸删除空格,目前正专注于构建文件 reader 部分。
修正:
我当前的问题是此代码 returns 来自第三行的 $StartPosition 数据和来自第四行的 $Length 数据,当它们都应该首先在 COMMA 的第一行中找到时。我不知道是什么促使了这种行为。
下一期:它只读取 practice_data.txt 中的第一条记录我猜这是我需要告诉 COMMA 回到开头的地方?
while (my $sourceLine = <SOURCE>) {
$StartPosition = 0;
$Length = 0;
$Output = "";
$NextRecord ="";
while (my $commaLine = <COMMA>) {
my $Comma = index($commaLine, ',');
print "Comma location found at $Comma \n";
$StartPosition = substr($commaLine, 0, $Comma);
print "Start position is $StartPosition \n";
$Comma = $Comma + 1
$Length = substr($commaLine, $Comma);
print "Length is $Length \n";
$NextRecord = substr($sourceLine, $StartPosition, $Length);
$Output = "$Output . ',' . $NextRecord";
}
print OUTPUT "$Output \n";
}
practice_data.txt
1234512345John Doe 123 Mulberry Lane Columbus Ohio 43215Johnny Jane
5432154321Jason McKinny 423 Thursday Lane Columbus Ohio 43212Jase Jamie
4321543212Mike Jameson 289 Front Street Cleveland Ohio 43623James Sarah
每条记录的长度为 100 个字符。
Definitions.txt:
0,10
10,10
20,10
30,20
50,10
60,10
70,5
75,15
90,10
您似乎对如何读取 COMMA 文件句柄的内容有些困惑。每次您读取 <COMMA>
时,您都在从该文件中读取另一行。相反,将一行读入像 my $line = <FH>
这样的标量并改用它:
while (my $source_line = <SOURCE>) {
$StartPosition = 0;
$Length = 0;
$Output = "";
$Input = $_;
$NextRecord ="";
while (my $comma_line = <COMMA>) {
my $Comma = index($comma_line, ',');
print "Comma location found at $Comma \n";
$StartPosition = substr($comma_line, 0, $Comma);
print "Start position is $StartPosition \n";
$Length = substr($comma_line, $Comma);
print "Length is $Length \n";
$NextRecord = substr($Input, $StartPosition, $Length) + ',';
$Output = "$Output$NextRecord";
}
print OUTPUT "$Output \n";
}
提供足够的信息总是有帮助的,这样我们至少可以进行一些测试,而不必阅读您的代码并想象数据的样子。
我建议您先使用包含字段规范的文件构建模板后使用 unpack
。请注意,A
字段说明符会删除数据中的尾随空格。
使用 Text::CSV
模块解析或生成格式正确的 CSV 数据几乎是必不可少的。而且我使用了 autodie
pragma 以避免必须显式检查和报告每个 I/O 操作的状态。
我用过这个数据
my_source_data.txt
12345678 ABCDE1234FGHIJK
my_field_spec.txt
0,8
10,5
15,4
19,6
还有这个节目
use strict;
use warnings;
use 5.010;
use autodie;
use Text::CSV;
my @template;
open my $field_fh, '<', 'my_field_spec.txt';
while ( <$field_fh> ) {
my (@info) = /\d+/g;
die unless @info == 2;
push @template, sprintf '@%dA%d', @info;
}
my $template = "@template";
open my $source_fh, '<', 'my_source_data.txt';
my $csv = Text::CSV->new( { binary => 1, eol => $/ } );
while ( <$source_fh> ) {
my @fields = unpack $template;
$csv->print(\*STDOUT, \@fields);
}
输出
12345678,ABCDE,1234,FGHIJK
已编辑:我正在尝试创建一个简短的脚本,该脚本需要一个输入固定宽度文件和一个具有每个属性的起始位置和长度的文件,然后将文件输出为 CSV 而不是固定宽度。我还没有搞砸删除空格,目前正专注于构建文件 reader 部分。
修正: 我当前的问题是此代码 returns 来自第三行的 $StartPosition 数据和来自第四行的 $Length 数据,当它们都应该首先在 COMMA 的第一行中找到时。我不知道是什么促使了这种行为。
下一期:它只读取 practice_data.txt 中的第一条记录我猜这是我需要告诉 COMMA 回到开头的地方?
while (my $sourceLine = <SOURCE>) {
$StartPosition = 0;
$Length = 0;
$Output = "";
$NextRecord ="";
while (my $commaLine = <COMMA>) {
my $Comma = index($commaLine, ',');
print "Comma location found at $Comma \n";
$StartPosition = substr($commaLine, 0, $Comma);
print "Start position is $StartPosition \n";
$Comma = $Comma + 1
$Length = substr($commaLine, $Comma);
print "Length is $Length \n";
$NextRecord = substr($sourceLine, $StartPosition, $Length);
$Output = "$Output . ',' . $NextRecord";
}
print OUTPUT "$Output \n";
}
practice_data.txt
1234512345John Doe 123 Mulberry Lane Columbus Ohio 43215Johnny Jane
5432154321Jason McKinny 423 Thursday Lane Columbus Ohio 43212Jase Jamie
4321543212Mike Jameson 289 Front Street Cleveland Ohio 43623James Sarah
每条记录的长度为 100 个字符。 Definitions.txt:
0,10
10,10
20,10
30,20
50,10
60,10
70,5
75,15
90,10
您似乎对如何读取 COMMA 文件句柄的内容有些困惑。每次您读取 <COMMA>
时,您都在从该文件中读取另一行。相反,将一行读入像 my $line = <FH>
这样的标量并改用它:
while (my $source_line = <SOURCE>) {
$StartPosition = 0;
$Length = 0;
$Output = "";
$Input = $_;
$NextRecord ="";
while (my $comma_line = <COMMA>) {
my $Comma = index($comma_line, ',');
print "Comma location found at $Comma \n";
$StartPosition = substr($comma_line, 0, $Comma);
print "Start position is $StartPosition \n";
$Length = substr($comma_line, $Comma);
print "Length is $Length \n";
$NextRecord = substr($Input, $StartPosition, $Length) + ',';
$Output = "$Output$NextRecord";
}
print OUTPUT "$Output \n";
}
提供足够的信息总是有帮助的,这样我们至少可以进行一些测试,而不必阅读您的代码并想象数据的样子。
我建议您先使用包含字段规范的文件构建模板后使用 unpack
。请注意,A
字段说明符会删除数据中的尾随空格。
使用 Text::CSV
模块解析或生成格式正确的 CSV 数据几乎是必不可少的。而且我使用了 autodie
pragma 以避免必须显式检查和报告每个 I/O 操作的状态。
我用过这个数据
my_source_data.txt
12345678 ABCDE1234FGHIJK
my_field_spec.txt
0,8
10,5
15,4
19,6
还有这个节目
use strict;
use warnings;
use 5.010;
use autodie;
use Text::CSV;
my @template;
open my $field_fh, '<', 'my_field_spec.txt';
while ( <$field_fh> ) {
my (@info) = /\d+/g;
die unless @info == 2;
push @template, sprintf '@%dA%d', @info;
}
my $template = "@template";
open my $source_fh, '<', 'my_source_data.txt';
my $csv = Text::CSV->new( { binary => 1, eol => $/ } );
while ( <$source_fh> ) {
my @fields = unpack $template;
$csv->print(\*STDOUT, \@fields);
}
输出
12345678,ABCDE,1234,FGHIJK