2015-11-15 2 views
1

У меня есть такой рода регулярного выражения:Regex + петля + ИЛИ

$recipes =~ s/ 

       ([^\.\/]) ($dimentions) (\s) ($unit) 
       |(\(?) ($wholeNumberDecimal) (\s) ($unit) 
       |(\(?) ($wholeNumber)  (\s) ($unit)  
       |(\(?) ($wholeNumberFraction) (\s) ($unit) 
       /transformer($1,$2,$3,$4) /eixg;  

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

Из моего преувеличения будет $1, $2, $3, $4. Если я передам все эти переменные методу, то как метод узнает, какая переменная является новым совпадением и какие из них могут быть сопоставлены раньше и просто запоминаются?

Есть ли способ иметь только одну переменную $1, которая подходит к любому из этих случаев и просто отправляет этот метод в любое время?

Или у меня есть правильный подход? Я пытаюсь сопоставить эти разные случаи с книгой рецептов и с каждым вызовом вызова метод, который преобразует это в эквивалент системы показателей.

Пример: 5 ст.л -> 80 мл, или 8 х 8 х 2 дюйма -> 20 х 20 х 5 см

На основании опубликованных ответов я изменил свое регулярное выражение:

$recepies =~ s/ 
        (?| 
        ([^\.\/]) ($dimentions) 
        | 
        (\(?) ($wholeNumberDecimal)  #ex: 1.5 
        | 
        (\(?) ($wholeNumber)   #ex: 1 
        | 
        (\(?) ($wholeNumberFraction) 
        ) 
        (\s) ($unit) 

        /transformer($1,$2,$3,$4) /eixg; #the replacement 

Кажется, это работает!

+0

Это может быть сделано лучше, чем [Regexp :: Grammars] (https://metacpan.org/pod/Regexp::Grammars). – Schwern

ответ

5

Вы ищете Alternative capture group numbering:

$recipes =~ s{ 
    (?| 
     ([^\.\/]) ($dimentions) 
     | 
     (\(?) ($wholeNumberDecimal) 
     | 
     (\(?) ($wholeNumber) 
     | 
     (\(?) ($wholeNumberFraction) 
    ) 
    (\s) 
    ($unit) 
}{ 
    transformer($1,$2,$3,$4) 
}eixg; 
+0

Они больше не называют его сбросом ветвей? – sln

+0

@sln Perl называет его «Альтернативная нумерация групп захвата», [PCRE] (http://www.pcre.org/pcre.txt) называет его «Дублировать номера подшаблонов», а также ссылается на него как «сброс ветвей». В большинстве руководств используется «сброс ветвей» ... Я думаю, вы можете выбрать тот, который вам больше нравится :) – Mariano

+1

@Mariano - Strange. Из Perl _5.20 perlre_ docs '(? | Pattern) Это шаблон« сброса ветвей », который имеет специальное свойство, которое группы захвата нумеруются из одной и той же начальной точки в каждой ветви чередования.« – sln

1

From my understatement there will be a $1, $2, $3, $4. If I pass all of those variables to the method then how will the method know which variable is the new match and which ones might have been matched before and are simply being remember

Я считаю, что эти переменные модифицируются на успешный матч.
С учетом под вид s///, есть только один способ, с правой стороны -
Доступен. То есть на успешном матче.
Таким образом, это не тот случай, когда он сопоставлен раньше, совпадение var's равно
всегда ток в этом случае.

Ниже приведено ваше регулярное выражение. Я предлагаю получить программное обеспечение, которое может это сделать
для вас. Я использовал RegexFormat 7.

([^\.\/])     # (1) 
    ($dimentions)    # (2) 
    (\s)      # (3) 
    ($unit)      # (4) 
| 
    (\(?)      # (5) 
    ($wholeNumberDecimal)  # (6) 
    (\s)      # (7) 
    ($unit)      # (8) 
| 
    (\(?)      # (9) 
    ($wholeNumber)    # (10) 
    (\s)      # (11) 
    ($unit)      # (12) 
| 
    (\(?)      # (13) 
    ($wholeNumberFraction)  # (14) 
    (\s)      # (15) 
    ($unit)      # (16) 

Как видите, в нем содержится 16 групп захвата.
Итак, группы 1-4 охватывают только ваши первые альтернативные разделы.

Regex должен быть спроектирован так, чтобы получить результат , который вы ожидаете.
Если вам все равно, какой раздел из 4 альтернативных вариантов соответствует,
, то вы можете использовать переменную захвата как флаг, а также получать данные.
В Perl, его часто используют

if (defined($1)) { 
    ## .. 
} 
elsif (defined ($2) { 
    ## ... 
} 
etc ... 

После некоторого факторинга это может быть сделано, как показано ниже.
И, если эти переменные содержат литералы вы должны обернуть их в
QuoteMeta построить как \Q $variable \E

Заметим также, что если переменные содержат постоянные данные (литералы или регулярное выражение)
они должны быть предварительно скомпилированных в начало вашей программы
как с цитатой регулярное выражение оператора my $regex = qr~...~;

Тогда просто положить его в свой обычный вызов, как это
$recipes =~ s/$regex/transformer($1,$2,$3,$4)/eixg;

Отметьте, что я считаю, что Perl может обладать своими захватами vars
как-то, но я немного ржавый, поэтому не могу вспомнить.

Если вам нужно передать в Варсе, просто использовать что-то вроде

sub transformer { 
    my ($var1,$var2,$var3,$var4) = @_; 
    ... 
} 

Ниже использует тот факт, что вы разработана группа захвата в качестве флагов
, а также.

sub transformer 
{ 
    my ($v1,$v2,$v3,$v4) = @_; 

    if (defined($v1)) { 
     return ...; 
    } 
    elsif (defined($v2)) { 
     return ...; 
    } 
    elsif (defined($v3)) { 
     return ...; 
    } 
    elsif (defined($v4)) { 
     return ...; 
    } 
} 


$recipes =~ s~ 

    (?: 
      [^./] 
      ($dimentions)    # (1) 
     | 
      \(? 
      (?: 
       ($wholeNumberDecimal)  # (2) 
      | ($wholeNumber)    # (3) 
      | ($wholeNumberFraction)  # (4) 
     ) 
    ) 
    \s 
    $unit 

~transformer($1,$2,$3,$4)~eixg; 
+0

Имея 16 групп захвата, вы слишком много думаете об этом? Плюс все эти утверждения. Нет ли способа иметь только 4 группы захвата. Потому что по существу только один случай будет истинным одновременно, и каждый случай требует только 4 группы захвата. –

+0

@ QasimAhmed - Конечно, 16 слишком много. Но я не сужу ни слова. В действительности, '\ s' и' $ unit' не нуждаются в захвате, они являются константами. '[^.]' не требует захвата, а также '\ (?' подмножество. Это оставляет 4 группы в 4 чередованиях (т. е. 4 различия). Не совсем работа для _branch reset_, если вы не хотите просто играть с регулярным выражением, – sln

Смежные вопросы