[英]How to read multi-line values from a file using Perl
I have a properties file, say 我有一个属性文件,比方说
##
## Start of property1
##
##
Property1=\
a:b,\
a1:b1,\
a2,b2
##
## Start of propert2
##
Property2=\
c:d,\
c1:d1,\
c2,d2
Note that the value for any given property may be split across multiple lines. 请注意,任何给定属性的值可以分为多行。
I want to read this property file using Perl. 我想用Perl读取这个属性文件。 This works fine in Java, as Java supports multi-line values using the backslash, but in Perl it is a nightmare.
这在Java中运行良好,因为Java使用反斜杠支持多行值,但在Perl中它是一个噩梦。
In the above properties file there are two properties - Property1
and Property2
- each associated with a string which I can split based on the delimiters ,
and :
在上面的属性文件中有两个属性 -
Property1
和Property2
- 每个Property2
都与一个字符串相关联,我可以根据分隔符进行拆分,
并且:
For a given property (say Property1
) and given column (say a1
) I need to return second column (here b1
) 对于给定的属性(比如
Property1
)和给定的列(比如a1
),我需要返回第二列(这里是b1
)
The code should be able to ignore comments, spaces, etc. 代码应该能够忽略注释,空格等。
Thanks in Advance 提前致谢
Most text processing - including handling backslash continuation lines - is very simple in Perl. 在Perl中,大多数文本处理(包括处理反斜杠延续行)都非常简单。 All you need is a read loop like this.
你只需要一个像这样的读取循环。
while (<>) {
$_ .= <> while s/\\\n// and not eof;
}
The program below does what I think you want. 下面的程序做我认为你想要的。 I have put a
print
call in the read loop to show the complete records that have been aggregated over continuation lines. 我在read循环中放置了一个
print
调用,以显示已经在continuation行上聚合的完整记录。 I have also demonstrated extracting the b1
field that you gave as an example, and shown the output from Data::Dump
so that you can see the data structure that is created. 我还演示了提取你给出的
b1
字段作为示例,并显示了Data::Dump
的输出,以便您可以看到创建的数据结构。
use strict;
use warnings;
my %data;
while (<DATA>) {
next if /^#/;
$_ .= <DATA> while s/\\\n// and not eof;
print;
chomp;
my ($key, $values) = split /=/;
my @values = map [ split /:/ ], split /,/, $values;
$data{$key} = \@values;
}
print $data{Property1}[1][1], "\n\n";
use Data::Dump;
dd \%data;
__DATA__
##
## Start of property1
##
##
Property1=\
a:b,\
a1:b1,\
a2,b2
##
## Start of propert2
##
Property2=\
c:d,\
c1:d1,\
c2,d2
output 产量
Property1=a:b,a1:b1,a2,b2
Property2=c:d,c1:d1,c2,d2
b1
{
Property1 => [["a", "b"], ["a1", "b1"], ["a2"], ["b2"]],
Property2 => [["c", "d"], ["c1", "d1"], ["c2"], ["d2"]],
}
Update 更新
I have read your question again and I think you may prefer a different representation of your data. 我再次阅读了您的问题,我认为您可能更喜欢不同的数据表示形式。 This variant keeps the proerty values as hashes instead of arrays of arrays, otherwise its behaviour is identical
此变体将proerty值保留为哈希值而不是数组数组,否则其行为是相同的
use strict;
use warnings;
my %data;
while (<DATA>) {
next if /^#/;
$_ .= <DATA> while s/\\\n// and not eof;
print;
chomp;
my ($key, $values) = split /=/;
my %values = map { my @kv = split /:/; @kv[0,1] } split /,/, $values;
$data{$key} = \%values;
}
print $data{Property1}{a1}, "\n\n";
use Data::Dump;
dd \%data;
output 产量
Property1=a:b,a1:b1,a2,b2
Property2=c:d,c1:d1,c2,d2
b1
{
Property1 => { a => "b", a1 => "b1", a2 => undef, b2 => undef },
Property2 => { c => "d", c1 => "d1", c2 => undef, d2 => undef },
}
Assuming your file isn't too large, here is a simple approach: 假设您的文件不是太大,这是一个简单的方法:
use strict;
use warnings;
open FILE, "my_file.txt" or die "Can't open file!";
{
local $/;
my $file = <FILE>;
#If \ is found at the end of the line, delete the following line break.
$file =~ s/\\\n//gs;
}
Any time a line ends with \\
, the following line break is removed. 每当一行以
\\
结尾时,将删除以下换行符。 This will put each multi-line property on a single line. 这会将每个多行属性放在一行上。
The downside is that this reads the entire file into memory; 缺点是这会将整个文件读入内存; you could adapt it to an algorithm that goes through the file line by line, if your input file is very large.
如果您的输入文件非常大,您可以将其调整为逐行遍历文件的算法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.