我有一个Perl程序,它通过目录并解析文本文件以获取某些信息。其中一条信息是分析块,如下所示:
*ANALYSIS_START* [analysis ID]
Line(s) = [multi- or single-line Line(s) data]
Reason Code = [single-line Reason Code data]
CR = [single-line CR data]
Note = [multi-line Note data]
[multi-line Note data]
*ANALYSIS_END*
文本文件可以包含零分析块,或者它可能具有这些分析块的任意数量 - 块数和每个块的大小都是未知的。我希望做的是在2D数组中收集这些块中的信息。例如,如果文本文件恰好有2个分析块,则2D数组看起来像这样:
$VAR1 = [
[
Lines = [multi- or single-line data]
Reason Code = [single-line data]
CR = [single-line data]
Note = [multi-line data]
[multi-line data]
]
[
Lines = [multi- or single-line data]
Reason Code = [single-line data]
CR = [single-line data]
Note = [multi-line data]
[multi-line data]
]
];
如果某人有更好的建议来收集数据,同时如上所示将每个分析块保持在一起,请告诉我们。可能有一个比我不知道的2D阵列更好的解决方案。
我对Perl相当新,但我了解如何通过查看this SO question来创建2D数组。问题是,我不确定如何使用我的特定情况填充2D数组。到目前为止,我有以下代码:
while (my $current_line = <$textfile>) {
# Code that gets other, single-line information from file
$pattern = '\*ANALYSIS_START\*';
if ($current_line =~ $pattern) { # Find Analysis Block
push @analysis_IDs, $1; # Get the analysis ID
while(<$textfile>) {
last if /\*ANALYSIS_END\*/; # Stop at block's end
push @analysis_info, $_; # Append each line of data
}
}
}
当然,这会导致我的数组看起来像这样,文件的每一行都是独立的,但分析块不是:
$VAR1 = ''
$VAR2 = 'Lines = [lines data]'
$VAR3 = 'Reason Code = [reason code data]'
$VAR4 = 'CR = [cr data]'
$VAR5 = 'Note = [note data]'
$VAR6 = ' [note data...]'
$VAR7 = ''
$VAR8 = 'Lines = [lines data]'
$VAR9 = 'Reason Code = [reason code data]'
$VAR10= 'CR = [cr data]'
$VAR11= 'Note = [note data]'
$VAR12= ' [note data...]'
我无法绕过如何遍历文件的每个部分以创建所需的2D数组。我可能只是盯着它看太久了。
如何创建我需要的数组?所有解释,仅限单词或带有代码示例的解释都非常受欢迎。
我的问题可以改进吗?请在评论中告诉我们!
答案 0 :(得分:2)
这是一种获取问题所需的方法,特别是通过使用数组数组。
use warnings;
use strict;
my $file = 'data_analysis.txt';
open my $fh, '<', $file or die "Can't open $file -- $!";
# Prepare (and compile) START/END paterns, capturing ID in START
my $start_pattern = qr|\*ANALYSIS_START\*\s*\[([^[]+)\]|;
my $end_pattern = qr(\*ANALYSIS_END\*);
my @analysis_IDs;
my @analysis_info;
while (my $line = <$fh>)
{
chomp($line);
# Code that gets other, single-line information from file
if ($line =~ $start_pattern .. $line =~ $end_pattern)
{
if ($line =~ $start_pattern) {
push @analysis_IDs, $1; # Get the analysis ID
push @analysis_info, []; # Add arrayref this block's lines
}
elsif (not $line =~ $end_pattern) {
push @{$analysis_info[-1]}, $line; # add to last []
}
}
}
print "$_\n" for @analysis_IDs;
use Data::Dumper;
print Dumper(\@analysis_info);
代码使用范围运算符..
来确定它在模式中的位置。这个有用的运算符可以跨迭代保持状态,因此它知道条件何时满足并且仍然是真的(或不是)。只要第二个条件保持为假,它就会在第一个条件变为(并保持)为真时评估为真。这使我们无法维护一个单独的变量来跟踪所有这些变量。见Range Operators in perlop。由于开始和结束模式需要不同的处理,因此它们(再次)在内部区分。这不是最有效的方式,但我希望它很清楚。
匹配可以使用$line =~ $pattern
代替$line =~ /$pattern/
,因为已使用qr
准备了已使用的模式。显式$line
用于寻求清晰,但可以(隐式)使用$_
来提供更紧凑的代码。特别是,范围条件简化为(/$start_pattern/ .. /$end_pattern/)
,我们现在需要分隔符。可以使用几乎任何分隔符(或一对),它也适用于qr
运算符。见Quote-like operators in perlop。请注意,我在上面的第一种情况下使用了qr|...|
,因此()
可以在内部自由使用,而在第二种情况下不可能使用,因为它们是分隔符。标准正则表达式文档是 - 教程perlretut,快速介绍perlrequick,完整语法perlre和参考perlreref。
使用这种方法,你可以保留一个带有分析ID的单独数组,另一个带有块的数组。他们通过指数达成一致,但这可能不是最可靠的系统。
相反,例如,可以使用数组的散列。然后,块的内容的匿名数组将是密钥的“值”,即ID。在这种情况下,您不会维护订单。这可以通过另一种辅助结构来解决,例如,如果需要的话。
以下是关于Arrays of Arrays的教程和Complex Data structures上的食谱。
答案 1 :(得分:0)
您需要的只是块的另一个数组。然后,当您点击下一个或最后一个块时,将其推入主阵列。
my @analysis_Ids;
my $current_analysis = [];
while (my $current_line = <$textfile>) {
push @$current_analysis, $_;
# if next one, push @analysis_Ids, $current_analysis; and reset $current_analysis;
}
# check for the final one.