我将文件中的数据作为单个字符串加载。我可以按照我想要的任何方式格式化文件。 例如。
multilne string
++++++++++++++
another multiline string
++++++++++++++++
yet another multiline string
etc
如何轻松干净地读取文件并将这些标记内的每个字符串(可以是我可以根据需要定义它们的任何内容)加载到数组中?
更新
可能是我不清楚。
我有一系列需要在perl中加载的文本。这些文本(多行字符串基本上没有什么特别的ascii字符非常简单)我打算将它们复制/粘贴到文件(来自不同的地方)。我想要的是以某种方式将它们/格式化存储在文件中,以便我可以轻松地将每个字符串/部分加载到数组中。
我提到这种格式,因为我认为这是一种简单的格式。如果您有更好的解决方案,请告诉我有关它的信息
答案 0 :(得分:5)
如果您可以按任何方式格式化文件,那么至少使分隔符完全相同。然后,您可以使用$/
变量来简化代码:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
$/ = "\n++\n";
chomp(my @lines = <DATA>);
say Dumper \@lines;
__DATA__
multilne string
++
another multiline string
++
yet another multiline string
etc
这给出了以下输出:
$VAR1 = [
'multilne string',
'another multiline string',
'yet another multiline string
etc
'
];
如果它适合您,您甚至可以使用空行并使用您将$/
设置为空字符串所获得的特殊行为。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
$/ = "";
chomp(my @lines = <DATA>);
say Dumper \@lines;
__DATA__
multilne string
another multiline string
yet another multiline string
etc
哪个输出:
$VAR1 = [
'multilne string',
'another multiline string',
'yet another multiline string
etc'
];
请注意,第二个版本甚至删除了最后一条记录中的额外换行符。
答案 1 :(得分:3)
如果数据的大小为slurp,您可以在感兴趣的行上拆分:
use strict;
use warnings;
my @data = split /^\++\s*\n/m, do { local $/; <DATA> };
use Data::Dump;
dd \@data;
__DATA__
multilne string
++++++++++++++
another multiline string
++++++++++++++++
yet another multiline string
etc
输出:
[
"multilne string \n",
"another multiline string \n",
"yet another multiline string \netc",
]
这类似于Recipe 6.7中的Perl Cookbook。
如果您担心整个文件的诽谤,只需使用memory map懒惰地访问它:
use File::Map 'map_file';
map_file my $map, '/tmp/data.txt', '+<' ;
my @lines = split /^\++\s*\n/m, $map ;
dd @lines;
# same output
您问'如果您有更好的解决方案,请告诉我。'
使用固定长度的不变分隔符,以便您可以将记录分隔符设置为该分隔符。 Dave Cross有great solution。
或者,如果您要使用变量分隔符,可以考虑将元数据嵌入其中。
考虑文件:
++ File 1
multilne string
++ File 2
another multiline string
++++++ File 3
yet another multiline string
etc
然后,您可以在分隔符中构建元数据的哈希值:
@_=split /^\++\s*(.*?(?=\s+\n|\z))\n?/m, $map;
shift @_ if ($_[0] eq '');
%h2=@_;
然后你知道你是如何标记每个部分的:
{
"File 1" => "multilne string \n",
"File 2" => "another multiline string \n",
"File 3" => "yet another multiline string \netc",
}
如果要将分隔符的顺序颠倒为:
multilne string
++ File 1
another multiline string
++ File 2
yet another multiline string
etc
++++++ File 3
你可以这样做:
while (my ($v, $k)=(shift @_, shift @_)) {
last unless defined $k;
$k=~s/\s*$//;
$h2{$k}=$v;
}
或者,
while ($map =~/^(.*?)(?=^\++|\z)^\++\s*(.*?(?=\s+\n|\z))\n?/gms) {
my $k=$2;
my $v=$1;
$k=~s/\s*$//;
$hash{$k}=$v;
}
答案 2 :(得分:2)
您可以使用$INPUT_RECORD_SEPARATOR
指定替代分隔符来分隔文件记录。
如果你想要段落,那么local $/ = '';
会分成2个或更多新行。
或者,如果您对自定义分隔符感兴趣,那么local $/ = "\n+++\n";
会在换行符上分割,然后是三个加号,然后是另一个换行符。
我建议您使用YAML
。
以下脚本从数据块加载3个段落。输出到YAML文件。将它们重新加载到新的数据结构中,然后输出结果。
use strict;
use warnings;
use YAML qw(DumpFile LoadFile);
# Load Data from __DATA__ block in paragraph mode
my $data = do {
local $/ = "";
[ map { chomp; $_ } <DATA> ];
};
# Output paragraphs to YAML file and then load back in
DumpFile('paragraphs.yaml', $data);
my $newdata = LoadFile('paragraphs.yaml');
# View format of YAML loaded data
use Data::Dump;
dd $newdata;
__DATA__
multiline string 1 line 1
multiline string 1 line 2
multiline string 1 line 3
multiline string 2 line 1
multiline string 2 line 2
multiline string 3 line 1
multiline string 3 line 2
multiline string 3 line 3
输出:
[
"multiline string 1 line 1\nmultiline string 1 line 2\nmultiline string 1 line 3",
"multiline string 2 line 1\nmultiline string 2 line 2",
"multiline string 3 line 1\nmultiline string 3 line 2\nmultiline string 3 line 3",
]
因为它是YAML,所以数据以人类可读和可编辑的格式存储在下面演示的paragraph.yaml
中。
但是,因为它是YAML,所以这种格式已经支持了您可能想要的所有数据结构,而无需像添加自定义格式那样添加更多代码。
---
- |-
multiline string 1 line 1
multiline string 1 line 2
multiline string 1 line 3
- |-
multiline string 2 line 1
multiline string 2 line 2
- |-
multiline string 3 line 1
multiline string 3 line 2
multiline string 3 line 3
答案 3 :(得分:1)
使用触发器操作符排除开头和结束行++++++++++++++
,
my $sep = "++++++++++++++";
my @arr;
while (<DATA>) {
my $range = /\Q$sep/ ... /\Q$sep/;
push @arr, $_ if $range >1 and $range !~ /E/;
}
print @arr;
__DATA__
multilne string
++++++++++++++
another multiline string
++++++++++++++++
yet another multiline string
etc
答案 4 :(得分:1)
您无法准确解释文件的格式,但从示例开始,它的分隔线完全由加号+
符号和可选的尾随空格组成。
这是一种糟糕的格式选择,但这会为你做到这一点。
请注意,如果要在命令行中指定输入文件的路径,只需将<DATA>
更改为<>
即可。
use strict;
use warnings;
my @data = ('');
while (<DATA>) {
if ( /^\++\s*$/ ) {
push @data, '';
}
else {
$data[-1] .= $_;
}
}
use Data::Dump;
dd \@data;
__DATA__
multilne string
++++++++++++++
another multiline string
++++++++++++++++
yet another multiline string
etc
<强>输出强>
[
"multilne string \n",
"another multiline string \n",
"yet another multiline string \netc",
]
答案 5 :(得分:-1)
这将做你想要的:
#!/usr/bin/perl
use warnings;
use strict;
my $sep = "+";
my @arr;
while (<DATA>) {
chomp;
next if /^[$sep]+?/;
push (@arr, $_);
}
print "@arr\n";
print $arr[0], "\n";
__DATA__
multilne string
++++++++++++++
another multiline string
++++++++++++++++
yet another multiline string
etc