2014-10-02 4 views
-1

Я хочу, чтобы Perl проверял, что строка содержит точно разделенный запятыми список цифр, а затем разбивает его на массив. Регулярное выражение /^(\d+)(?:,(\d+))*$/) делает синтаксический анализ, который я хочу, но когда я его оцениваю в контексте списка, я получаю только первую и последнюю цифры. Я попробовал /(?:^|,)(\d+)(?=,|$)/g, чтобы принести модификатор g в игру, чтобы испустить несколько совпадений, но это не позволяет полностью проверить синтаксис, как показано в примере ниже. Итак, как мне получить полностью привязанное регулярное выражение, такое как первое, чтобы испустить массив из нескольких совпадений до ()*?Perl regex для разбора «1,2,3» в массив чисел

foreach (@ARGV) { 
    #if (my @numbers = /^(\d+)(?:,(\d+))*$/) { 
    if (my @numbers = /(?:^|,)(\d+)(?=,|$)/g) { 
    print "$_ = (@numbers)\n"; 
    } else { 
    print "$_ isn't a number list!\n"; 
    } 
} 

Поместите в файл с названием numberlist.pl и запустить его, и вы получите это: -

bash$ perl numberlist.pl 1,2,3 ,1,2,3 1,2,3, a,2,3 1,b,3 1,2,c aa1,2,3zz 
1,2,3 = (1 2 3) 
,1,2,3 = (1 2 3) 
1,2,3, = (1 2 3) 
a,2,3 = (2 3) 
1,b,3 = (1 3) 
1,2,c = (1 2) 
aa1,2,3zz = (2) 

Если раскомментировать первый if и комментарий второе, то вы получите это: -

1,2,3 = (1 3) 

поэтому содержимое () внутри (?:) испускает одно совпадение, а не список совпадений.

Я знаю, что я мог бы использовать первое регулярное выражение для проверки синтаксиса, а затем my @numbers = split /,/, чтобы получить массив, но есть больше, чем один способ сделать это. Я просто не могу понять, как это сделать. Помогите!

+1

Вместо добавления этого комментария ко всем трем ответам, я добавлю это на вопрос. Вы, вероятно, ** не ** хотите использовать '\ d'. Вместо этого используйте '[0-9]'. '\ d' соответствует всем интересным символам цифр Юникода, таким как« 3 »и« ߃ »и« 3 »и« ୩ »и« 3 ». – tobyink

ответ

0

Только нужно регулярное выражение для фильтрации не-номера. split полезнее здесь:

for (@ARGV) { 
    next unless $_; # Add this to skip processing of blank entries. 
    my @l = grep {/^\d+\z/} split /,/; 
    print "$_ = (@l)\n"; 
} 

Как было отмечено, это будет относиться к пустой строке как пустой список. Это может быть или не быть так, как вы хотите, чтобы он работал.

Если вы не возражаете против возможности \n в конце входной строки, измените \z на $ в шаблоне.

+0

Он считает пустую строку списком чисел. Это может быть нежелательно. – ikegami

+0

Это может быть или не быть, но без заявленного требования в любом случае это просто спекуляция с нашей стороны. Тем не менее, я уверен, что я не хочу, чтобы '\ z' включал новые строки в мой блок grep. – md4

+0

Кроме того, существуют более эффективные способы защиты от пустых строк. – md4

0

Я рекомендовал бы отделяя Проверяющий от разбора:

use strict; 
use warnings; 

local @ARGV = do { 
    no warnings 'qw'; 
    qw(1,2,3 ,1,2,3 1,2,3, a,2,3 1,b,3 1,2,c aa1,2,3zz); 
}; 

for (@ARGV) { 
    if (/^\d+(?:,\d+)*$/) { 
     my @numbers = split ','; 
     print "Numbers are @numbers\n"; 
    } else { 
     print "NaN = $_\n"; 
    } 
} 

Выходов:

Numbers are 1 2 3 
NaN = ,1,2,3 
NaN = 1,2,3, 
NaN = a,2,3 
NaN = 1,b,3 
NaN = 1,2,c 
NaN = aa1,2,3zz 

Однако, если вы привязаны к соединив их, а затем проверить, используя положительное опережение утверждения и захват снаружи, например:

for (@ARGV) { 
    if (my @numbers = /\G(?=\d+(?:,\d+)*$)(\d+),?/g) { 
     print "Numbers are @numbers\n"; 
    } else { 
     print "NaN = $_\n"; 
    } 
} 
Смежные вопросы