В настоящее время у меня есть следующее регулярное выражение:

^\s*(.+)(?:[-\._ ]+)(\d+)\s*[xX]\s*(\d+)

Это будет соответствовать show_3x01_ep. name и извлекать show, 3, 01. Я хотел бы расширить это, чтобы можно было снимать несколько эпизодов. Например:

 show _3x01_3x02 ep. name

Должен вернуться:

show, 3, 01, 3, 02

Не мог бы кто-нибудь объяснить мне, как это можно сделать?

0
user2268507 20 Ноя 2014 в 06:12

3 ответа

Лучший ответ

Вы слишком многого ожидаете от своего регулярного выражения. Самый простой способ - сделать это в два этапа.

Прежде всего, обратите внимание, что (.+), который соответствует show в вашем примере, является слишком общим. Если вы примените шаблон к show _3x01_3x02 ep. name, вы получите show - с завершающим пробелом - потому что следующий [-._ ]+ (нет необходимости экранировать точку или заключать класс символов в (?: ... )) удовлетворяется только одним символом.

Это сделает то, о чем вы просите. Он находит первую строку буквенных символов, а затем все пары строк цифр, которые разделены одним x.

use strict;
use warnings;

my $s = 'show _3x01_3x02 ep. name';

if ( my ($prefix) = $s =~ /([a-z]+)/i ) {
  print "$prefix\n";
  print "$1 $2\n" while $s =~ /(\d+)x(\d+)/g;
}

вывод

show
3 01
3 02
1
Borodin 20 Ноя 2014 в 06:35
Спасибо за это Бородину. Прочитав это, я решил начать с нуля и попытаться упростить вещи.
 – 
user2268507
21 Ноя 2014 в 02:10

Используйте модификатор Perl g

Вы можете использовать Perl-модификатор регулярного выражения g для поиска шаблона более одного раза в строке. Затем вы можете сохранить эти совпадения в списке, а затем что-то сделать с этим списком или его отдельными элементами. Например:

$ echo 'show _3x01_3x02 ep.name' |
      perl -ne '@words = ($_ =~ /\A(.*?)(?=\d)|(\d+)x(\d+)/g);
                @words = grep { $_ ne "" } @words;
                while (my $idx = each @words) {
                    @words[$idx] =~ s/^\s+|\s+\b|_//g;
                };
                print join(", ", @words), "\n"'
show, 3, 01, 3, 02
0
Todd A. Jacobs 20 Ноя 2014 в 08:28

Вместо этого используйте String # scan в Ruby

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

str = 'show _3x01_3x02 ep. name'
str.scan(/\A(.*?)(?=\d)|(\d+)x(\d+)/).
    flatten.compact.map { |e| e.gsub(?_, ' ').strip }
#=> ["show", "3", "01", "3", "02"]

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

  1. Сопоставьте все от начала строки до первой цифры в названии шоу.
  2. Сопоставьте все пары сезона / эпизода, которые он сможет найти.
  3. Вернуть все совпадения в виде массива.
  4. Сглаживайте вложенные массивы, созданные группами захвата, и отбрасывайте ноль.
  5. Замените подчеркивания пробелами в каждом элементе массива.
  6. Удаляет любые окружающие пробелы из каждого члена массива.
  7. Верните массив.

Само регулярное выражение совместимо с Perl, но остальная логика опирается на String # scan и другие внутренние компоненты, которые могут не отображаться непосредственно на Perl. YMMV.

-1
Community 23 Май 2017 в 15:27