Как я могу сделать $ 1 возвращаемых альтернатив без подстановочного регулярного выражения? - PullRequest
3 голосов
/ 22 января 2010

Проект, который я недавно присоединил, абстрагирует логику в элементы кода и базы данных Бизнес-логика, такая как xPaths, регулярные выражения и имена функций, вводится в базу данных, а общий код, такой как чтение файлов, создание xml из xpaths и т. Д., Находится в базе кода.

Большинство (если не все) методов, использующих регулярные выражения, структурированы следующим образом:

if ( $entry =~ /$regex/ ) { $req_value = $1; }

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

Выпуск:

Результат для следующих строк должен быть либо

'2.6.9-78.1.6.ELsmp (SMP)' or '2.6.9-78.1.6.ELsmp'

в зависимости от наличия SMP. $ 1 не достаточно для $ entry [0].

$entry[0] = qq|Linux version 2.6.9-78.1.6.ELsmp (brewbuilder@hs20-bc2-2.build.redhat.com) (gcc version 3.4.6 20060404 (Red Hat 3.4.6-10)) #1 SMP Wed Sep 24 05:41:12 EDT 2008|;
$entry[1] = qq|Linux version 2.6.9-78.0.5.ELsmp (brewbuilder@hs20-bc2-2.build.redhat.com) (gcc version 3.4.6 20060404 (Red Hat 3.4.6-10)) #1 Wed Sep 24 05:41:12 EDT 2008|;

Отсюда мое решение:

my $mutable = '';
my $regex = qr/((\d.*?)\s+(?:.*)?(SMP)((?{$mutable="$2 ($3)"}))|(\d.*?))\s+/;
if ($entry[$i] =~ /$regex/) {
    $req_value = $1; 
    $req_value = $mutable if ($mutable ne '');
    $mutable = '';
}

К сожалению, наличие «переменной» в базе данных делает это решение неприемлемым.

Мои вопросы:

  1. Как я могу очистить вышеуказанное решение, чтобы сделать его приемлемым с доступной структурой?

    или

  2. Как использовать регулярное выражение подстановки со структурой 'if ($ entry = ~ / $ regex /)'?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 22 января 2010

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

if (my @fields = $_ =~ /$pat/) {
  $req_value = join " " => grep defined($_), @fields;
}

Это работает, потому что успешное совпадение регулярного выражения в контексте списка возвращает все захваченные подстроки, , т.е. , $1, $2, $3 и т. Д., В зависимости от ситуации.

С одним рисунком,

qr/(\d+(?:[-.]\w+)*)(?:.*(SMP))?/

код выше дает 2.6.9-78.1.6.ELsmp SMP и 2.6.9-78.0.5.ELsmp in $req_value. grep defined($_) отфильтровывает перехваты для неиспользованных подшаблонов. Без этого вы получите предупреждения с неопределенным значением для случая без SMP.

Недостатком является то, что каждое регулярное выражение необходимо будет пересмотреть, чтобы убедиться, что все группы захвата действительно должны войти в $req_value. Например, скажем, кто-то использует шаблон

qr/(XYZ) OS (version \d+|v-\d+)/

Как и сейчас, только XYZ будет входить в $req_value, но использование приведенного выше обобщения также будет включать номер версии. Если это нежелательно, регулярное выражение должно быть

qr/(XYZ) OS (?:version \d+|v-\d+)/

потому что (?:...) не захватывает (то есть, он не выдает $2 для шаблона выше): это только для группировки.

0 голосов
/ 07 февраля 2010

Начиная с 5.10.0, (?|pattern) доступно, чтобы позволить альтернативам использовать ту же нумерацию захвата. Как вы указали, что вы все еще используете 5.8, это может быть не полезно напрямую, но, возможно, как дополнительный стимул для вашего проекта начать переход на современный Perl.

0 голосов
/ 22 января 2010

Я не совсем понимаю ваши ограничения. Вы ограничены в предоставлении одного регулярного выражения, которое всегда будет обрабатываться с использованием кода в первом отрывке? Если это так, вы не можете делать то, что вы пытаетесь сделать. Вы пытаетесь извлечь две отдельные части строки ввода, вы просто не можете вернуть 2 значения в одном скалярном возвращаемом значении, если вы не можете добавить код для их объединения.

Можете ли вы вообще добавить Perl-код? Например, вы можете определить логику:

if ( $entry =~ /$regex/ ) { $req_value = '$1 $2'; }

где твой $regex = qr/((\d.*?)\s+(?:.*)?(SMP)/;?

Обнажая способность определять какой-то новый код на Perl, вы не сможете этого сделать.

Относительно части второй, замены. Я интерпретирую ваш вопрос, чтобы спросить, можете ли вы скомпилировать обе части PATTERN и REPLACEMENT в s / PATTERN / REPLACEMENT / в один qr //. Если это так, вы не можете. qr // только компилирует соответствующий шаблон, а переменная qr может использоваться только в части PATTERN в REPLACEMENT. Другими словами, чтобы использовать s ///, вам нужно написать Perl-код, который запускает s ///. Я предполагаю, что если бы вы могли написать новый код на Perl, вы бы использовали вышеуказанное решение.

Еще одна мысль: в вашей нынешней архитектуре вы можете определить поля в терминах других полей? Другими словами, не могли бы вы извлечь строку версии с одним регулярным выражением, строку SMP с другим регулярным выражением и определить третье поле, которое объединяет два?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...