Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在perl中将某些匹配字符串之间的所有行打印到不同的文件中_Perl - Fatal编程技术网

如何在perl中将某些匹配字符串之间的所有行打印到不同的文件中

如何在perl中将某些匹配字符串之间的所有行打印到不同的文件中,perl,Perl,我对perl脚本编写相当陌生,需要一些帮助。以下是我的疑问: 我有一个文件,其内容如下: AA ABC 0 0 line1 line2 ... AA XYZ 1 1 line.. line.. AA GHI 2 2 line.. line... 现在我想得到那些行之间的所有行,它们都有起始字符串/模式“AA”,并将它们写入文件ABC.txt,XYZ.txt,GHI.txt,分别包括AA*,例如ABC.txt应该是这样的 AA ABC 0 0 line1 line2... AA XYZ 1

我对perl脚本编写相当陌生,需要一些帮助。以下是我的疑问:

我有一个文件,其内容如下:

AA ABC 0 0 
line1
line2
...
AA XYZ 1 1
line..
line..
AA GHI 2 2
line..
line...
现在我想得到那些行之间的所有行,它们都有起始字符串/模式
“AA”
,并将它们写入文件
ABC.txt
XYZ.txt
GHI.txt
,分别包括
AA*
,例如
ABC.txt
应该是这样的

AA ABC 0 0
line1
line2...
AA XYZ 1 1
line..
line..
XYZ.txt
应该是

AA ABC 0 0
line1
line2...
AA XYZ 1 1
line..
line..
希望我在这个问题上是清楚的,任何有关这方面的帮助都是非常感谢的

谢谢,
桑迪

我想你是在要求一个算法,因为你没有指定你需要什么帮助

  • 声明用于输出的文件句柄
  • 虽然尚未到达输入文件的结尾,
  • 读一行
  • 如果是标题行,
  • 解析它
  • 确定文件名
  • (重新)打开输出文件
  • 将该行打印到输出文件句柄

  • 为了避免您使用自我发布上述内容以来发布的糟糕解决方案之一,下面是代码:

    my $fh;
    while (<>) {
       if (my ($fn) = /^AA\s+(\S+)/) {
          $fn .= '.txt';
          open($fh, '>', $fn)
             or die("Can't create file \"$fn\": $!\n");
       }
    
       print $fh $_;
    }
    
    my$fh;
    而(){
    如果(my($fn)=/^AA\s+(\s+/){
    $fn.='.txt';
    开放式($fh,“>”,$fn)
    或者死亡(“无法创建文件\“$fn\”:$!\n”);
    }
    打印$fh$;
    }
    
    可能的改进,所有这些都很容易添加:

    • 检查重复的标题。(
      如果-e$fn
      是一种方式)
    • 检查第一个标题之前的数据。(
      如果!$fh
      是单向)

    一次只需打开一个文件。。。当一行与
    XYZ
    匹配时,打开
    XYZ.txt
    文件并输出该行。您将该文件保持打开状态(假设它是句柄
    当前_文件
    ),并将每个后续行输出到该文件,直到匹配新的头行。然后关闭当前文件并打开另一个文件

    我的Perl非常陈旧,因此我认为我无法提供编译代码,但本质上它与此非常接近

    my $current_name = "";
    
    foreach my $line (<INPUT>)
    {
        my($name) = $line =~ /^AA (\w+)/;
        if( $name ne $current_name ) {
            close(CURRENT_FILE) if $current_name ne "";
            open(CURRENT_FILE, ">>", "$name.txt") || die "Argh\n";
            $current_name = $name;
        }
        next if $current_name eq "";
        print CURRENT_FILE $line;
    }
    
    close(CURRENT_FILE) if $current_name ne "";
    
    my$current_name=”“;
    foreach我的$line()
    {
    我的($name)=$line=~/^AA(\w+)/;
    如果($name ne$当前名称){
    如果$CURRENT_name ne“”,则关闭(当前_文件);
    打开(当前_文件“>>”,“$name.txt”)|| die“Argh\n”;
    $current_name=$name;
    }
    下一步如果$current_name eq“”;
    打印当前_文件$line;
    }
    如果$CURRENT_name ne“”,则关闭(当前_文件);
    
    你觉得这个怎么样

    1:从文件中获取内容(可能使用file::Slurp的read_文件)并保存到标量

    use File::Slurp qw(read_file write_file);
    my $contents = read_file($filename);
    
    2:具有与以下类似的正则表达式模式匹配:

    my @file_rows = ($contents ~= /(AA\s[A-Z]{3}\s+\d+\s+\w*)/);
    
    3:如果第2列值在整个文件中始终是唯一的:

    foreach my $file_row (@file_rows) {
        my @values = split(' ', $file_row, 3);
        write_file($values[1] . ".txt", $file_row);
    }
    
    3:否则:拆分行值。使用第二列作为键将它们存储到散列中。使用哈希将数据写入输出文件

    my %hash;
    foreach my $file_row (@file_rows) {
        my @values = split(' ', $file_row, 3);
        if (defined $hash{$value[1]}) {
            $hash{$values[1]} .= $file_row;
        } else {
            $hash{$values[1]} = $file_row;
        }
    }
    
    foreach my $key (keys %hash) {
        write_file($key .'txt', $hash{$key});
    }
    

    这里有一个选项,用于查找与每条记录开头匹配的模式。当找到时,它循环遍历数据文件的行并构建一条记录,直到再次找到相同的模式或eof,然后将该记录写入文件。在写入文件之前,它不会检查文件是否已经存在,因此如果文件已经存在,它将替换ABC.txt:

    use strict;
    use warnings;
    
    my $dataFile    = 'data.txt';
    my $nextLine    = '';
    my $recordRegex = qr/^AA\s+(\S+)\s+\d+\s+\d+/;
    
    open my $inFH, '<', $dataFile or die $!;
    
    RECORD: while ( my $line = <$inFH> ) {
        my $record = $nextLine . $line;
    
        if ( $record =~ $recordRegex ) {
            my $fileName = $1 . '.txt';
    
            while ( $nextLine = <$inFH> ) {
                if ( $nextLine =~ $recordRegex or eof $inFH ) {
                    $record .= $nextLine if eof $inFH;
    
                    open my $outFH, '>', $fileName or die $!;
                    print $outFH $record;
                    close $outFH;
    
                    next RECORD;
                }
    
                $record .= $nextLine;
            }
        }
    }
    
    close $inFH;
    
    使用严格;
    使用警告;
    my$dataFile='data.txt';
    我的$nextLine='';
    我的$recordRegex=qr/^AA\s+(\s+)\s+\d+\s+\d+/;
    打开我的$inFH、、$fileName或die$!;
    打印$outph$记录;
    关闭$outph;
    下一个记录;
    }
    $record.=$nextLine;
    }
    }
    }
    关闭$inFH;
    
    希望这有帮助


    编辑:此代码替换有问题的原始代码。谢谢你,回顾原始代码。

    谢谢@阿蒙,用于修复我的代码=)多年的C++已经剥夺了我编写Perl的能力,当我没有一个解释程序,如果数据行包含序列<代码> AA/code >,它将被分割在中间。考虑将<代码> $/< /COD> > <代码> \ NAA > /COD>,尽管第一行必须是特殊的用例。删除记录分隔符也称为
    chomp
    ing,因此无需使用替换。@amon-非常感谢您批评原始代码。奇怪的是,我没有把
    $/
    chomp
    联系起来,所以谢谢你提醒我。原来的代码问题太大,所以被替换了。以上尝试与OP的记录开始相匹配,因此可能更加健壮。感谢Kenosis,这很有帮助。我以前也做过类似的事情,但是你的代码可以做到。我现在唯一的问题是,如果我有多行,如AA ABC 0 0 line1 line2 AA ABC 1 line3 line4,我需要在同一个文件中同时使用这两行,使我能够更新已创建的ABC.txt文件,而不是在文件中显示第3行和第4行。我自己也在试着做一些修改,但你方的任何帮助都会更有帮助。@Santy-非常欢迎你。正则表达式处理您的数据,生成所有三个文本文件,并按要求提供名称和内容。由于您在条件中放置了一个
    打印
    ,并且它没有被执行,这确实表明正则表达式与记录的开头不匹配。因为您可以完全查看这些数据,所以也许您可以成功地稍微调整一下正则表达式。让我知道…@Kenosis:调整了regexp并工作得很好,我现在唯一的问题是,如果我有多行,比如AA ABC 0 0 line1 line2 AA ABC 1 line3 line4,我需要将它们都放在同一个文件中,使我能够更新已创建的abc.txt文件,而不是在新文件中显示第3行和第4行。为了始终将整个文件保存在内存中,您经历了很多麻烦?另外,我不理解第二点,但它不会像你写的那样起作用。提示:它甚至不编译。您可能想使用
    split
    或其他方法。用
    split
    s