2016-02-08 2 views
3

Я пытаюсь использовать Perl или MATLAB для анализа нескольких чисел из одной строки текста. Моя текстовая строка:Совпадение шаблона раздвижного окна в регулярных выражениях perl или matlab

t10_t20_t30_t40_

сейчас в MATLAB, я использовал следующий сценарий

str = 't10_t20_t30_t40_'; 
a = regexp(str,'t(\d+)_t(\d+)','match') 

и возвращает

a = 

't10_t20' 't30_t40' 

То, что я хочу, чтобы она также возвращает ' t20_t30 ', так как это, очевидно, совпадение. Почему regexp не сканирует его?

Таким образом, я обратился к Perl, и написал следующее в Perl:

#!/usr/bin/perl -w 
$str = "t10_t20_t30_t40_"; 
while($str =~ /(t\d+_t\d+)/g) 
{ 
    print "$1\n"; 
} 

и результат такой же, как MATLAB

t10_t20 
t30_t40 

, но я действительно хотел «t20_t30» также быть в Результаты.

Может ли кто-нибудь сказать мне, как это сделать? Благодаря!

[обновление с помощью решения]: С помощью коллег я определил решение, используя так называемое «утверждение обхода», предоставляемое Perl.

#!/usr/bin/perl -w 
$str = "t10_t20_t30_t40_"; 
while($str =~ m/(?=(t\d+_t\d+))/g) 
{print "$1\n";} 

Ключом является использование «утверждения с нулевой шириной взгляда» в Perl. Когда Perl (и другие подобные пакеты) использует regexp для сканирования строки, он не пересканирует то, что уже было проверено в последнем матче. Таким образом, в приведенном выше примере t20_t30 никогда не будет отображаться в результатах. Чтобы зафиксировать это, нам нужно использовать поиск с нулевой шириной для сканирования строки, создавая совпадения, которые не исключают подстроки из последующих поисков (см. Рабочий код выше). Поиск начнется с нулевой позиции и увеличивается на один раз, насколько это возможно, если к поиску (т. Е. M // g) добавляется модификатор «global», что делает его «жадным» поиском.

Это объясняется более подробно в this blog post.

Выражение (? = T \ d + _t \ d +) соответствует любой строке ширины 0, за которой следует t \ d + _t \ d +, и это создает фактическое «скользящее окно». Это эффективно возвращает ВСЕ t \ d + _t \ d + шаблоны в $ str без исключения, поскольку каждая позиция в $ str является строкой шириной 0. Дополнительная скобка фиксирует рисунок при выполнении скользящего совпадения (? = (T \ d + _t \ d +)) и, таким образом, возвращает желаемый результат скользящего окна.

ответ

0

После того, как алгоритм regexp нашел матч, совпавшие символы не учитывается при дальнейших матчах (и, как правило, это то, что хочет, например .* является не должны соответствовать всем мыслимым смежным подстрокам этого поста).Обходной бы начать поиск снова один символ после первого матча, и собрать результаты:

str = 't10_t20_t30_t40_'; 
sub_str = str; 
reg_ex = 't(\d+)_t(\d+)'; 
start_idx = 0; 
all_start_indeces = []; 
all_end_indeces = []; 
off_set = 0; 
%// While there are matches later in the string and the first match of the 
%// remaining string is not the last character 
while ~isempty(start_idx) && (start_idx < numel(str)) 
    %// Calculate offset to original string 
    off_set = off_set + start_idx; 
    %// extract string starting at first character after first match 
    sub_str = sub_str((start_idx + 1):end); 
    %// find further matches 
    [start_idx, end_idx] = regexp(sub_str, reg_ex, 'once'); 
    %// save match if any 
    if ~isempty(start_idx) 
     all_start_indeces = [all_start_indeces, start_idx + off_set]; 
     all_end_indeces = [all_end_indeces, end_idx + off_set]; 
    end 
end 
display(all_start_indeces) 
display(all_end_indeces) 
matched_strings = arrayfun(@(st, en) str(st:en), all_start_indeces, all_end_indeces, 'uniformoutput', 0) 
+0

Это хорошее решение, но моя репутация слишком низкая на сайте, что я не могу его проголосовать ... извините –

2

Использование Perl:

#!/usr/bin/perl 
use Data::Dumper; 
use Modern::Perl; 

my $re = qr/(?=(t\d+_t\d+))/; 

my @l = 't10_t20_t30_t40' =~ /$re/g; 
say Dumper(\@l); 

Выход:

$VAR1 = [ 
      't10_t20', 
      't20_t30', 
      't30_t40' 
     ];