如何在Perl中将多行文件读入块中?

时间:2016-05-30 10:03:23

标签: perl

我有一个包含以下文字的文件。

#L_ENTRY    <s_slash_1>
#LEX        </>
#ROOT       </>
#POS        <sp>
#SUBCAT     <slash>
#S_LINK           <>
#BITS    <>
#WEIGHT      <0.1>
#SYNONYM     <0>

#L_ENTRY    <s_comma_1>
#LEX        <,>
#ROOT       <,>
#POS        <sp>
#SUBCAT     <comma>
#S_LINK           <>
#BITS    <>
#WEIGHT      <0.1>
#SYNONYM     <0>

#L_ENTRY    <s_tilde_1>
#LEX        <~>
#ROOT       <~>
#POS        <sp>
#SUBCAT     <tilde>
#S_LINK           <>
#BITS    <>
#WEIGHT      <0.1>
#SYNONYM     <0>

#L_ENTRY    <s_at_1>
#LEX        <@>
#ROOT       <@>
#POS        <sp>
#SUBCAT     <at>
#S_LINK           <>
#BITS    <>
#WEIGHT      <0.1>
#SYNONYM     <0>

我知道如何使用Perl将线条变成数组,但在这种情况下,我想创建一个包含两个元素的数组。每个以#L_ENTRY开头,以#SYNONYM <0>结尾。

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:1)

如果将输入记录分隔符变量设置为空字符串,则perl将在段落模式中工作,并在输入数据中以一个或多个空行分隔的时间返回一个块< / p>

GameObject clone = Instantiate(mockup, transform.position, Quaternion.Euler(Vector3.zero)) as GameObject;

输出

use strict;
use warnings 'all';

local $/ = '';


my $n;
while ( <DATA> ) {
    printf "Block %d:\n<<%s>>\n\n", ++$n, $_;
}

__DATA__
A
B
C
D
E
F

A
B
C
D
E
F

答案 1 :(得分:0)

有两种方法可以做到这一点。首先,您可以设置“输入记录分隔符”特殊变量(请参阅更多here)。简而言之,您告诉Perl一行不会被新行字符终止。在您的情况下,您可以将其设置为'#SYNONYM&lt; 0&gt;'。然后,当您在一行中读取时,您可以在具有该标记的文件中获得所有内容 - 如果标记不在那里,那么您将获得文件中剩下的内容。因此,对于看起来像这样的输入数据;

#L_ENTRY        <s_slash_1>
#LEX         </>
#ROOT        </>
#POS         <sp>
#SUBCAT      <slash>
#S_LINK            <>
#BITS     <>
#WEIGHT      <0.1>
#SYNONYM     <0>

#L_ENTRY        <s_comma_1>
#LEX         <,>
#ROOT        <,>
#POS         <sp>
#SUBCAT      <comma>
#S_LINK            <>
#BITS     <>
#WEIGHT      <0.1>
#SYNONYM     <0>

如果你运行它;

use v5.14;
use warnings;

my $filename = "data.txt" ;
open(my $fh, '<', $filename) or die "$filename: $!" ;
local $/ = "#SYNONYM     <0>\n" ;
my @chunks = <$fh> ;
say $chunks[0] ;
say '---' ;
say $chunks[1] ;

你得到;

#L_ENTRY        <s_slash_1>
#LEX         </>
#ROOT        </>
#POS         <sp>
#SUBCAT      <slash>
#S_LINK            <>
#BITS     <>
#WEIGHT      <0.1>
#SYNONYM     <0>

---

#L_ENTRY        <s_comma_1>
#LEX         <,>
#ROOT        <,>
#POS         <sp>
#SUBCAT      <comma>
#S_LINK            <>
#BITS     <>
#WEIGHT      <0.1>
#SYNONYM     <0>

关于此的几点说明;

  1. 您的记录之间的任何额外数据将“陷入网络”并最终在每条记录的开头;
  2. 记录分隔符本身仍然是数据的一部分,位于每条记录的末尾。
  3. 为了获得更多控制,最好逐行处理数据并使用正则表达式在“捕获”模式和“不捕获”模式之间切换:

    use v5.14;
    use warnings;
    
    my $filename = "data.txt" ;
    open(my $fh, '<', $filename) or die "$filename: $!" ;
    
    my $found_start_token = qr/ \s* \#L_ENTRY \s* /x;
    my $found_stop_token  = qr/ \s* \#SYNONYM \s+ \<0\> \s* \n /x;
    
    my @chunks ;
    my $chunk  ;
    my $capture_mode = 0 ;
    
    while ( <$fh> )  {
        $capture_mode = 1 if /$found_start_token/ ;
        $chunk .= $_ if $capture_mode ;
        if (/$found_stop_token/) {
            push @chunks, $chunk ;
            $chunk = '' ;
            $capture_mode = 0 ;
        }
    }
    say $chunks[0] ;
    say '---' ;
    say $chunks[1] ;
    exit 0
    

    几个笔记;

    1. 如果我们处于捕获模式,程序将按当前行$_的字符串连接工作。{/ li>
    2. 在“扩展模式”$chunk中使用正则表达式关闭并打开捕获模式。这允许在正则表达式中添加空格以便于阅读。
    3. 记录之间的额外数据将出现在块中。
    4. 它产生与以前相同的输出。

答案 2 :(得分:0)

从这个和your succeeding question看起来你有答案但却没有意识到它

只要您的块被至少一个空行隔开,您就可以使用Perl的段落模式,它会将块中的文本移回

这是我希望你理解的另一个不同的例子。我创建了一个名为templateCache的文件,其中包含您发布的数据,并以段落模式打开它

输出来自Data::Dump,我只用它来证明生成的数组恰好包含了你要求的四个字符串

如果您需要更多解释,请在此解决方案中添加评论

test.txt

输出

use strict;
use warnings 'all';
use autodie;

my $file = 'test.txt';

my @chunks = do {
    open my $fh, '<', $file;
    local $/ = '';
    <$fh>;
};

use Data::Dump;
dd \@chunks;