如何在perl中将某些匹配字符串之间的所有行打印到不同的文件中
我对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
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