Как сопоставить ровно две пустые строки - PullRequest
1 голос
/ 08 января 2011

У меня вопрос по регулярным выражениям.У меня есть файл, и мне нужно проанализировать его таким образом, чтобы я мог различить некоторые конкретные блоки текста в нем.Эти блоки текста разделены двумя пустыми строками (есть блоки, которые разделены 3 или 1 пустыми строками, но мне нужно ровно 2).Итак, у меня есть кусок кода, и это регулярное выражение \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);

Ура, Юлия

Ответы [ 4 ]

5 голосов
/ 08 января 2011

По умолчанию Perl читает файлы по очереди, поэтому вы не увидите несколько новых строк.Следующий код выделяет текст, оканчивающийся двойной новой строкой.

    local $/ = "\n\n" ;

    while (<> ) {

      print "-- found $_" ;
    }
1 голос
/ 09 января 2011

Новый ответ

После проблем, исключающих> 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);
0 голосов
/ 09 января 2011
use 5.012;

open my $fh,'<','1.txt';

#slurping file
local $/;
my $content = <$fh>;

close $fh;

for my $block ( split /(?<!\n)\n\n\n(?!\n)/,$content ) {
    say 'found:';
    say $block;
}
0 голосов
/ 09 января 2011

Устаревший в пользу нового ответа

Ответ justintime работает, говоря perl, что вы хотите назвать конец строки "\ n \ n", что является умными будет хорошо работать. Единственным исключением является то, что это должно точно соответствовать.При использовании используемого вами регулярного выражения создается впечатление, что в «пустых» строках могут быть пробелы, и в этом случае это не сработает.Кроме того, его метод разделит даже более чем на 2 переноса строки, что не было разрешено в ОП.

Для полноты, чтобы сделать это так, как вы просили, вам нужно вылить весь файл в переменную (еслифайл не такой большой, чтобы использовать всю вашу память, вероятно, в большинстве случаев нормально).

Тогда я бы, вероятно, сказал бы использовать функцию 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
);  

Затем вы можете выполнять операции с массивом.Если я понимаю ваш комментарий к ответу justintime, вы хотите записать каждый блок в отдельный файл.Это будет выглядеть примерно так:

my $file_num = 1;
foreach my $block (@blocks) {
  open(my $out, '>', $file_num++ . ".txt");
  print $out $block;
}

Обратите внимание, что, поскольку вы открываете $ лексически (с помощью my), когда он достигает конца блока foreach, переменная $ out умирает (то есть "выходит из области видимости«).Когда это происходит с лексическим дескриптором файла, файл автоматически закрывается.И вы можете сделать то же самое с методом justintime:

local $/ = "\n\n" ;

my $file_num = 1;
while (<>) {
  open(my $out, '>', $file_num++ . ".txt");
  print $out $block;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...