2017-01-27 4 views
0

Я хочу использовать регулярное выражение Perl для извлечения определенных значений из имен файлов. Они имеют следующие (действительные) имена:Извлечение определенных значений из регулярного выражения Perl

testImrrFoo_Bar001_off 
testImrrFooBar_bar000_m030 
testImrrFooBar_bar231_p030 

Из сказанного выше я хотел бы извлечь первые 3 цифры (всегда гарантированно будут 3), а последнюю часть строки, после последнего _ (который либо off, либо (m или p), а затем 3 цифры). Итак, первое, что я хотел бы извлечь, - это 3 цифры, вторая - строка.

И я вышел со следующим способом (я понимаю, что это может быть не самым оптимальным/самым хорошими один):

my $marker = '^testImrr[a-zA-z_]+\d{3}_(off|(m|p)\d{3})$'; 
if ($str =~ m/$marker/) 
{ 
    print "1=$1 2=$2"; 
} 

Где только $1 имеет действительный результат (а именно последний бит информации я хочу), но $2 получается пустой. Любые идеи о том, как получить эти 3 цифры в середине?

ответ

5

Вы были почти там.

Просто:
- захватить три цифры, добавив скобки вокруг: (\d{3})
- не захват m|p путем добавления ?: после скобки перед ним ((?:m|p)), или с помощью [mp] вместо:

^testImrr[a-zA-z_]+(\d{3})_(off|[mp]\d{3})$ 

И вы получите:

1=001 2=off 
1=000 2=m030 
1=231 2=p030 
+1

Чёрт! Так близко. Клянусь, после X лет много практики я получу эти кровавые регулярные выражения ...! –

+0

@ titus.andronicus, вы можете перейти на https://regex101.com/, чтобы проверить свои регулярные выражения, он также дает вам то, что находится внутри ваших групп захвата, действительно полезно помочь отладке регулярных выражений;) –

2

вы можете захватить бо го сразу, например с

if ($str =~ /(\d{3})_(off|(?:m|p)\d{3})$/) { 
    print "1=$1, 2=$2".$/; 
} 

You например, имеет две группы захвата, а также (off|(m|p)\d{3} и m|p). В случае первого имени файла для второй группы захвата ничего не вылавливается из-за соответствия другой ветке. Для групп, не связанных с захватом, используйте (?:yourgroup).

1

Там действительно нет необходимости в регулярных выражениях, когда будет достаточно простой split и substr:

use strict; 
use warnings; 

while (<DATA>) { 
    chomp; 
    my @fields = split(/_/); 
    my $digits = substr($fields[1], -3); 

    print "1=$digits 2=$fields[2]\n"; 
} 

__DATA__ 
testImrrFoo_Bar001_off 
testImrrFooBar_bar000_m030 
testImrrFooBar_bar231_p030 

Выход:

1=001 2=off 
1=000 2=m030 
1=231 2=p030