如何将文件中的字符串段加载到数组中?

时间:2014-09-05 15:07:48

标签: regex perl file

我将文件中的数据作为单个字符串加载。我可以按照我想要的任何方式格式化文件。 例如。

multilne string  
++++++++++++++  
another multiline string  
++++++++++++++++  
yet another multiline string   
etc

如何轻松干净地读取文件并将这些标记内的每个字符串(可以是我可以根据需要定义它们的任何内容)加载到数组中?

更新
可能是我不清楚。
我有一系列需要在perl中加载的文本。这些文本(多行字符串基本上没有什么特别的ascii字符非常简单)我打算将它们复制/粘贴到文件(来自不同的地方)。我想要的是以某种方式将它们/格式化存储在文件中,以便我可以轻松地将每个字符串/部分加载到数组中。
我提到这种格式,因为我认为这是一种简单的格式。如果您有更好的解决方案,请告诉我有关它的信息

6 个答案:

答案 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

我建议您使用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