2016-11-29 3 views
1
@matches = ($filestr =~ /^[0-9]+\. (.+\n)*/mg); 

У меня есть файл, который был считан в filestr, но по какой-то причине выше регулярное выражение, которое должно соответствовать начало строки, с последующим числом, точкой, пробел, а затем любое количество строк, за которыми следует новая строка (при этом заканчивается, когда на ней есть строка с только новой строкой), похоже, просто выдает некоторые отдельные строки из файла.Почему это не Perl регулярное выражение работы

Когда я сделать что-то вроде

@matches = ($filestr =~ /^[0-9]+\. .+\n/mg); 

я правильно сопрягать одну строку.

Когда я делаю это

@matches = ($filestr =~ /^[0-9]+\. .+\n.+\n/mg); 

Я соответствую тем же отдельным строкам, а затем каким-то, казалось бы, не связанными линиями. Что случилось с моим регулярным выражением?

Примечание: регулярное выражение отлично работает в этом тесте регулярного выражения: https://regex101.com/, он просто не будет работать в perl.

Пример, в данном тексте:

1. This should 
match 

2. This should too 

3. This 
one 
also 

регулярное выражение должно соответствовать

1. This should 
match 

и

2. This should too 

и

3. This 
one 
also 
+0

Просто FYI: когда разрывы строк вступают в игру, используйте '\ r' вместо' \ n'. Однако здесь лучше всего изменить весь подход и прочитать по очереди, проверяя каждый последующий. –

+0

Спасибо за предложение. Я просто попробовал \ R, но получаю тот же результат, что и с \ n. –

+0

Знаете ли вы, что вы можете проверить линию за строкой так, как вы предложили? Похоже, я, по сути, ручно разделял бы регулярное выражение.Сначала проверьте, соответствует ли строка^[0-9] + \. , затем проверяем соответствие строки + \ n для остальной части первой строки и всех последующих строк (пока я не получил строку с единственной новой строкой на ней, после чего мне пришлось бы перезапустить). –

ответ

2

Ваше регулярное выражение является правильным. Но вы частично фиксируете результат. Я бы предложил вам собрать весь матч в единый результирующий набор, и вот как он будет храниться в @matches.

Итак, правильное регулярное выражение будет /(^[0-9]+\. (?:.+\n)*)/gm. Таким образом, вы получаете результат с результатом $1. Вывод его в программу дает.

Хотя, он будет работать, не сохраняя эти скобки (...) также потому, что по умолчанию он принимает $& (т.е. весь матч), если вы ничего не захватили. Итак, помните, что в этих случаях вы должны использовать non-capturing group(?: ...) вместо группы ().

#!/usr/bin/perl 
use strict; 
use warnings; 
use Data::Dumper; 

my $str = ' 
1. This should 
match 

2. This should too 

3. This 
one 
also 
'; 

my @matches = $str =~ /^([0-9]+\. (?:.+\n)*)/gm; 

print Dumper(\@matches); 

Выход:

[ 
      '1. This should 
match 
', 
      '2. This should too 
', 
      '3. This 
one 
also 
' 
     ]; 
1

В этой ситуации вместо чтения файла за строкой вы должны прочитать его по абзацу. Для этого вам нужно установить $/ в пустую строку. пример:

use strict; 
use warnings; 

my @result; 

{ 
    local $/ = ""; 
    while (<DATA>) { 
     chomp; 
     push @result, $_ ; 
     # or to filter paragraphs that don't start with a digit, use instead: 
     # push @result, $_ if /^[0-9]+\./; 
    } 
} 


__DATA__ 
1. This should 
match 

2. This should too 

3. This 
one 
also 
Смежные вопросы