Regex 如何精确匹配两个空行
我有一个关于正则表达式的问题。我有一个文件,我需要以这样一种方式解析它,我可以区分其中一些特定的文本块。这些文本块由两个空行分隔。有些文本块由3或1个空行分隔,但我需要2个。所以我有一段代码,这是\s*$^\s*$/正则表达式,我认为应该匹配,但它不匹配。 怎么了Regex 如何精确匹配两个空行,regex,perl,parsing,Regex,Perl,Parsing,我有一个关于正则表达式的问题。我有一个文件,我需要以这样一种方式解析它,我可以区分其中一些特定的文本块。这些文本块由两个空行分隔。有些文本块由3或1个空行分隔,但我需要2个。所以我有一段代码,这是\s*$^\s*$/正则表达式,我认为应该匹配,但它不匹配。 怎么了 $filename="yu"; open($in,$filename); open(OUT,">>out.text"); while($str=<$in>) { unless($str = /^\s*$^\s*
$filename="yu";
open($in,$filename);
open(OUT,">>out.text");
while($str=<$in>)
{
unless($str = /^\s*$^\s*$/){
print "yes";
print OUT $str;
}
}
close($in);
close(OUT);
干杯,
Yuliya默认情况下,Perl一次读取一行文件,因此不会看到多行新行。以下代码选择以双新行结尾的文本
local $/ = "\n\n" ;
while (<> ) {
print "-- found $_" ;
}
默认情况下,Perl一次读取一行文件,因此您不会看到多个新行。以下代码选择以双新行结尾的文本
local $/ = "\n\n" ;
while (<> ) {
print "-- found $_" ;
}
反对赞成新答案
justintime的答案是告诉perl您想调用一行的结尾\n\n,这很聪明,而且会很好地工作。一个例外是,这必须完全匹配。根据您使用的正则表达式,它使空行上似乎有空格,在这种情况下,这将不起作用。此外,他的方法甚至会在2个以上的换行符上分裂,这在OP中是不允许的
为了完整性,要按照您要求的方式执行,如果文件不太大,无法使用所有内存,则需要将整个文件拼凑成一个变量,在大多数情况下,这可能很好
然后,我可能会说使用split函数将文本块分割成一组块。然后,您的代码将类似于:
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'yu';
my $text;
open(my $fh, '<', $file);
{
local $/; enables slurp mode inside this block
$text = <$fh>;
}
close($fh);
my @blocks = split(
/
(?<!\n)\n #check to make sure there isn't another \n behind this one
\s*\n #first whitespace only line
\s*\n #second "
(?!\n) #check to make sure there isn't another \n after this one
/x, # x flag allows comments and whitespace in regex
$text
);
请注意,由于当$out到达foreach块的末尾时,使用my按词汇打开$out,因此$out变量失效,即超出范围。当词法文件句柄发生这种情况时,该文件将自动关闭。你也可以用justintime的方法做类似的事情:
local $/ = "\n\n" ;
my $file_num = 1;
while (<>) {
open(my $out, '>', $file_num++ . ".txt");
print $out $block;
}
反对赞成新答案
justintime的答案是告诉perl您想调用一行的结尾\n\n,这很聪明,而且会很好地工作。一个例外是,这必须完全匹配。根据您使用的正则表达式,它使空行上似乎有空格,在这种情况下,这将不起作用。此外,他的方法甚至会在2个以上的换行符上分裂,这在OP中是不允许的
为了完整性,要按照您要求的方式执行,如果文件不太大,无法使用所有内存,则需要将整个文件拼凑成一个变量,在大多数情况下,这可能很好
然后,我可能会说使用split函数将文本块分割成一组块。然后,您的代码将类似于:
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'yu';
my $text;
open(my $fh, '<', $file);
{
local $/; enables slurp mode inside this block
$text = <$fh>;
}
close($fh);
my @blocks = split(
/
(?<!\n)\n #check to make sure there isn't another \n behind this one
\s*\n #first whitespace only line
\s*\n #second "
(?!\n) #check to make sure there isn't another \n after this one
/x, # x flag allows comments and whitespace in regex
$text
);
请注意,由于当$out到达foreach块的末尾时,使用my按词汇打开$out,因此$out变量失效,即超出范围。当词法文件句柄发生这种情况时,该文件将自动关闭。你也可以用justintime的方法做类似的事情:
local $/ = "\n\n" ;
my $file_num = 1;
while (<>) {
open(my $out, '>', $file_num++ . ".txt");
print $out $block;
}
新答案
在排除了2条以上的空行之后,在这里睡个好觉是一个更好的方法,甚至不需要发出咕噜声
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'yu';
my @blocks; #each element will be an arrayref, one per block
#that referenced array will hold lines in that block
open(my $fh, '<', $file);
my $empty = 0;
my $block_num = 0;
while (my $line = <$fh>) {
chomp($line);
if ($line =~ /^\s*$/) {
$empty++;
} elsif ($empty == 2) { #not blank and exactly 2 previous blanks
$block_num++; # move on to next block
$empty = 0;
} else {
$empty = 0;
}
push @{ $blocks[$block_num] }, $line;
}
#write out each block to a new file
my $file_num = 1;
foreach my $block (@blocks) {
open(my $out, '>', $file_num++ . ".txt");
print $out join("\n", @$block);
}
事实上,您不必稍后存储和写入,只需在运行时对每个块写入一个文件即可:
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'yu';
open(my $fh, '<', $file);
my $empty = 0;
my $block_num = 1;
open(OUT, '>', $block_num . '.txt');
while (my $line = <$fh>) {
chomp($line);
if ($line =~ /^\s*$/) {
$empty++;
} elsif ($empty == 2) { #not blank and exactly 2 previous blanks
close(OUT); #just learned this line isn't necessary, perldoc -f close
open(OUT, '>', ++$block_num . '.txt');
$empty = 0;
} else {
$empty = 0;
}
print OUT "$line\n";
}
close(OUT);
新答案
在排除了2条以上的空行之后,在这里睡个好觉是一个更好的方法,甚至不需要发出咕噜声
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'yu';
my @blocks; #each element will be an arrayref, one per block
#that referenced array will hold lines in that block
open(my $fh, '<', $file);
my $empty = 0;
my $block_num = 0;
while (my $line = <$fh>) {
chomp($line);
if ($line =~ /^\s*$/) {
$empty++;
} elsif ($empty == 2) { #not blank and exactly 2 previous blanks
$block_num++; # move on to next block
$empty = 0;
} else {
$empty = 0;
}
push @{ $blocks[$block_num] }, $line;
}
#write out each block to a new file
my $file_num = 1;
foreach my $block (@blocks) {
open(my $out, '>', $file_num++ . ".txt");
print $out join("\n", @$block);
}
事实上,您不必稍后存储和写入,只需在运行时对每个块写入一个文件即可:
#!/usr/bin/perl
use strict;
use warnings;
my $file = 'yu';
open(my $fh, '<', $file);
my $empty = 0;
my $block_num = 1;
open(OUT, '>', $block_num . '.txt');
while (my $line = <$fh>) {
chomp($line);
if ($line =~ /^\s*$/) {
$empty++;
} elsif ($empty == 2) { #not blank and exactly 2 previous blanks
close(OUT); #just learned this line isn't necessary, perldoc -f close
open(OUT, '>', ++$block_num . '.txt');
$empty = 0;
} else {
$empty = 0;
}
print OUT "$line\n";
}
close(OUT);
由两条空线分隔的块是什么意思?如何描述一个有效的块,您能举个例子吗?^和$匹配字符串的开头和结尾,而不是行。要匹配行的开始/结束,您需要添加/m regex修饰符:$x=~/^line1$^line2$/m结果是比我最初认为的更棘手的问题。欢迎来到SO。用两条空线分隔的街区是什么意思?如何描述一个有效的块,您能举个例子吗?^和$匹配字符串的开头和结尾,而不是行。要匹配行的开始/结束,您需要添加/m regex修饰符:$x=~/^line1$^line2$/m结果是比我最初认为的更棘手的问题。欢迎来到SO。在这个例子中,整个文件是一堆有效的块。结束一个相关的问题。如何使用perl将每个文本块写入另一个文本文件?我的意思是,如果我有几个区块,我想将它们写入另一个文件,可能会有50个这样的区块,我不能再同意这种方法了。这将无法正确处理>2个空行,也无法处理空行但仍包含空格的行,正如OP的正则表达式所指出的那样。这是一个聪明的想法。在这个例子中,整个文件是一堆有效的块。结束一个相关的问题。我如何用perl将每个文本块写入另一个文本文件?我的意思是,如果我有几个区块,我想将它们写入另一个文件,可能会有50个这样的区块,我不能再同意这种方法了。这将无法正确处理2条以上的空行
并且不会处理空行但仍包含空格的行,正如OP的正则表达式所指出的那样。这是一个聪明的想法。@gangabass,你当然是对的,我将把它转换为正确的形式,它首先本地化$。在我匆忙发帖的过程中,我忘了你必须在标量上下文中这样做,如果我改为在列表上下文中调用,这会起作用,但随后必须再次加入和拆分。更正。我也放弃了让OP的正则表达式工作,取而代之的是我的正则表达式。所以我在排除三个空行时遇到了问题。有谁能弄明白为什么会这样。此外,我认为为了简化,可能有必要使用s/^\s*$//。我将在这里展示该方法,甚至展示它的一些混乱和陷阱。我添加了一种新方法,它似乎工作得更高效、更有效、更可靠understandably@gangabass,您是对的,当然,我会将它切换到正确的格式,首先本地化$/的格式。在我匆忙发帖的过程中,我忘了你必须在标量上下文中这样做,如果我改为在列表上下文中调用,这会起作用,但随后必须再次加入和拆分。更正。我也放弃了让OP的正则表达式工作,取而代之的是我的正则表达式。所以我在排除三个空行时遇到了问题。有谁能弄明白为什么会这样。此外,我认为为了简化,可能有必要使用s/^\s*$//。我将在这里展示该方法,甚至展示它的一些混乱和陷阱。我添加了一种新方法,它似乎工作得更高效、更有效、更容易理解。你加入消极的前瞻/落后检查是正确的。忘记了OP不需要有3个空行。大概只需要5.012或5.010就可以说了-只是检查没有什么不微妙的事情。你正确地把消极的前瞻/落后检查。忘记了OP不需要3个空行。大概只需要5.012或5.010就可以了-只是检查没有什么不微妙的事情发生。