如何将文件放入数组并将其保存在perl中

时间:2011-07-10 07:20:42

标签: perl

大家好我是perl的初学者,我遇到了一些问题,因为我想把我的字符串从AA开始到\ in到一个数组并想要保存它。 txt文件中有大约2000-3000个字符串,从相同的首字母开始,即AA到/我这样做是因为如果我错了,请纠正我。

输入文件

AA  c0001
BB  afsfjgfjgjgjflffbg
CC  table
DD  hhhfsegsksgk
EB  jksgksjs
\
AA  e0002
BB  rejwkghewhgsejkhrj
CC  chair
DD  egrhjrhojohkhkhrkfs
VB  rkgjehkrkhkh;r
\

源代码

$flag = 0
while ($line = <ifh>)
{

    if ( $line = m//\/g)
    {
        $flag = 1;
    }
    while ( $flag != 0)
    {
        for ($i = 0; $i <= 10000; $i++)
        { # Missing brace added by editor
            $array[$i] = $line;
        } # Missing brace added by editor
    }
}  # Missing close brace added by editor; position guessed!
print $ofh, $line;

close $ofh;

4 个答案:

答案 0 :(得分:8)

欢迎使用StackOverflow。

您的代码存在多个问题。首先,请发布可编辑的Perl;我不得不添加三个大括号来给它最小的编译机会,我不得不猜测其中一个去了哪一个(而且我应该在print语句的另一侧有一个中等的可能性。它)。

接下来,专家们:

use warnings;
use strict;

在他们的脚本的顶部,因为他们知道如果他们不这样做,他们会错过。作为一个学习者,你必须这样做;它会阻止你犯错误。

有了这些,您必须在使用它们时声明变量。

接下来,请记住缩进代码。这样做可以更容易理解。 Perl在最好的时候可能是不可理解的;不要让它变得更难。 (你可以决定你喜欢大括号的位置 - 这对讨论是开放的,虽然选择你喜欢的风格并坚持下去比较简单,忽略任何讨论,因为讨论可能会毫无结果。)

数据中的EB与VB是否显着?很难猜到。

目前还不清楚你究竟是在追求什么。可能是你在一个条目数组之后,一个用于文件中的每个块(其中块在仅包含反斜杠的行结束),并且数组中的每个条目都是由前两个字母键入的哈希值该行的(或第一个单词),该行的其余部分为该值。这是一个非常复杂的结构,可能超出了你在学习Perl的过程中预期会使用的结构。

您有while ($line = <ifh>)行。如果您以旧式方式打开文件,这在Perl中无效,但这不是您应该学习的方式。您没有显示输出文件句柄是如何打开的,但在尝试打印时会使用现代表示法。但是,那里也有一个错误:

print $ofh, $line;  # Print two values to standard output
print $ofh  $line;  # Print one value  to $ofh

您需要仔细研究代码,并考虑循环逻辑。我确定你所拥有的不是你所需要的。但是,我不确定你需要什么。

更简单的解决方案

来自评论:

  

我想将从AA到\的每条记录标记为记录0,直到记录n,并希望将其保存在包含所有记录号的新文件中。

然后你可能只需要:

#!/usr/bin/env perl
use strict;
use warnings;
my $recnum = 0;
while (<>)
{
    chomp;
    if (m/^\\$/)
    {
        print "$_\n";
        $recnum++;
    }
    else
    {
        print "$recnum $_\n";
    }
}

这将从命令行中指定的文件(或标准输入,如果没有)中读取,并将标记的输出写入标准输出。除了“记录结束”标记行之外,它的前缀是记录号和空格。选择输出格式和文件处理以满足您的需求。你可能会说chomp会适得其反;你可以在没有它的情况下编写程序代码。

过于复杂的解决方案

在提问者没有明确指示的情况下发展

这是一种可能的读取数据的方法,但它使用适度高级的Perl(哈希引用等)。 Data::Dumper模块对于打印出Perl数据结构也很有用(请参阅:perldoc Data::Dumper)。

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;

my @data;
my $hashref = { };
my $nrecs = 0;

while (<>)
{
    chomp;
    if (m/^\\$/)
    {
        # End of group - save to data array and start new hash
        $data[$nrecs++] = $hashref;
        $hashref = { };
    }
    else
    {
        m/^([A-Z]+)\s+(.*)$/;
        $hashref->{$1} = $2;
    }
}

foreach my $i (0..$nrecs-1)
{
    print "Record $i:\n";
    foreach my $key (sort keys $data[$i])
    {
        print "  $key = $data[$i]->{$key}\n";
    }
}
print Data::Dumper->Dump([ \@data ], [ '@data' ]);

示例输出,例如输入:

Record 0:
  AA = c0001
  BB = afsfjgfjgjgjflffbg
  CC = table
  DD = hhhfsegsksgk
  EB = jksgksjs
Record 1:
  AA = e0002
  BB = rejwkghewhgsejkhrj
  CC = chair
  DD = egrhjrhojohkhkhrkfs
  VB = rkgjehkrkhkh;r
$@data = [
           {
             'EB' => 'jksgksjs',
             'CC' => 'table',
             'AA' => 'c0001',
             'BB' => 'afsfjgfjgjgjflffbg',
             'DD' => 'hhhfsegsksgk'
           },
           {
             'CC' => 'chair',
             'AA' => 'e0002',
             'VB' => 'rkgjehkrkhkh;r',
             'BB' => 'rejwkghewhgsejkhrj',
             'DD' => 'egrhjrhojohkhkhrkfs'
           }
         ];

请注意,除了记录号之外,此数据结构未针对搜索进行优化。如果您需要以其他方式搜索数据,则需要以不同方式对其进行组织。 (并且不要将这些代码作为你的答案而不理解它 - 它是微妙的。它也没有错误检查;当心有缺陷的数据。)

答案 1 :(得分:2)

这不可能是正确的。我可以看到你的while循环有两个主要问题。

进入以下循环后

while ( $flag != 0)
{
  ...
}

你永远不会爆发,因为你找不到断线就不会重置旗帜。如有必要,您必须解析输入并退出循环。

第二,你从来没有读过这个循环中的任何输入,因此一遍又一遍地处理相同的$line

您不应该将循环放在代码中,而是可以使用以下模式(伪代码)

if flag != 0
    append item to array
else
    save array to file
    start with new array
end

答案 2 :(得分:2)

我相信你想要的是在\拆分文件内容,虽然它不太清楚。 要实现此目的,您可以通过设置输入记录分隔符将文件粘贴到变量中,然后拆分内容。

要了解与文件处理程序相关的Perl特殊变量,请阅读perlvar

#!perl

use strict;
use warnings;

my $content;

{
    open my $fh, '<', 'test.txt';
    local $/; # slurp mode
    $content = <$fh>;
    close $fh;
}

my @blocks = split /\\/, $content;

确保本地化修改Perl的特殊变量,以免干扰程序的不同部分。

如果您想保留分隔符,可以将$/直接设置为\并跳过拆分。

#!perl

use strict;
use warnings;

my @blocks;

{
    open my $fh, '<', 'test.txt';
    local $/ = '\\'; # seperate at \
    @blocks = <$fh>;
    close $fh;
}

答案 3 :(得分:1)

这是一种将数据读入数组的方法。正如我在评论中所说,将这些数据“保存”到文件是没有意义的,除非你改变它。因为如果我要将下面的@data数组打印到文件中,它会像输入文件一样完全

所以,在我们给你一个关于如何做的答案之前,你需要告诉我们你想要完成的是什么。

此脚本遵循以下规则(确切地说):

  • 找到以“AA”开头的行, 并将其保存到$line
  • 连接每个新行 归档到$line
  • 当您找到以。开头的行时 反斜杠\,停止连接 行并将$line保存到@data
  • 然后,找到下一行开头 用“AA”开始循环。

这些匹配的正则表达式非常宽松,因为它们也匹配AAARGH\bonkers。如果你需要它们更严格,你可以尝试/^\\$//^AA$/,但是你需要注意行的开头和结尾的空格。所以也许/^\s*\\\s*$//^\s*AA\s*$/代替。

代码:

use warnings;
use strict;

my $line="";
my @data;

while (<DATA>) {
    if (/^AA/) {
        $line = $_;
        while (<DATA>) {
            $line .= $_;
            last if /^\\/;
        }
    }
    push @data, $line;
}

use Data::Dumper;
print Dumper \@data;

__DATA__
AA  c0001
BB  afsfjgfjgjgjflffbg
CC  table
DD  hhhfsegsksgk
EB  jksgksjs
\
AA  e0002
BB  rejwkghewhgsejkhrj
CC  chair
DD  egrhjrhojohkhkhrkfs
VB  rkgjehkrkhkh;r
\