2013-08-04 7 views
3

У меня есть следующие команды LaTeX:PHP preg_match_all: параметры экстракта команды

\autocites[][]{}[][]{} 

где параметры внутри [] являются необязательными другими внутренними {} являются обязательными. Команда \autocites может быть расширен дополнительными группами аргументов, как:

\autocites[a1][a2]{a3}[b1][b2]{b3} 
\autocites[a1][a2]{a3}[b1][b2]{b3}[c1][c2]{c3} 
... 

Он также может быть использован, как это:

\autocites{a}{b} 
\autocites{a}[b1][]{b3} 
\autocites{a}[][b2]{b3} 
... 

Я хотел бы, чтобы извлечь его параметры, используя регулярное выражение в PHP , Это моя первая попытка:

/\\autocites(\[(.*?)\])(\[(.*?)\])(\{(.*?)\})(\[(.*?)\])(\[(.*?)\])(\{(.*?)\})/ 

Хотя это работает отлично, если \autocites содержит только две группы из трех параметров я не могу понять, как заставить ее работать на неизвестное количество параметров.

Я также попытался использовать следующее выражение:

/\\autocites((\[(.*?)\]\[(.*?)\])?\{(.*?)\}){2,}/ 

На этот раз я в состоянии соответствовать даже большему числу параметров, но тогда я не в состоянии извлечь все значения, потому что PHP всегда просто дает мне содержание последних трех параметров:

Array 
(
    [0] => Array 
     (
      [0] => \autocites[a][b]{c}[d][e]{f}[a][a]{a} 
     ) 

    [1] => Array 
     (
      [0] => [a][a]{a} 
     ) 

    [2] => Array 
     (
      [0] => [a][a] 
     ) 

    [3] => Array 
     (
      [0] => a 
     ) 

    [4] => Array 
     (
      [0] => a 
     ) 

    [5] => Array 
     (
      [0] => a 
     ) 

) 

Любая помощь будет принята с благодарностью.

+2

Возможно, проще всего совместить всю команду, включая случайные '(\ {. \} | \ [. \]) *' Вариации. Затем используйте второй 'preg_match_all' для извлечения отдельных параметров. В качестве альтернативы используйте '? (DEFINE)' или, по крайней мере, модификатор '/ x', чтобы создать управляемое регулярное выражение. – mario

ответ

2

Вам нужно сделать это в два этапа. Только .NET может извлекать произвольное количество захватов. Во всех других вариантах количество результирующих захватов фиксируется количеством групп в вашем шаблоне (повторение группы будет только перезаписывать предыдущие снимки).

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

preg_match('/\\\\autocites((?:\{[^}]*\}|\[[^]]*\])+)/', $input, $autocite); 
preg_match_all('/(?|\{([^}]*)\}|\[([^]]*)\])/', $autocite[1], $parameters); 
// $parameters[1] will now be an array of all parameters 

Workingdemo.

Используя несколько более сложный подход и якорь \G мы могли также делать все за один раз, используя произвольное количество совпадений вместо захватов:

preg_match_all('/ 
    (?|    # two alternatives whose group numbers both begin at 1 
     \\\\autocites # match the command 
     (?|\{([^}]*)\}|\[([^]]*)\]) 
        # and a parameter in group 1 
    |    # OR 
     \G   # anchor the match to the end of the last match 
     (?|\{([^}]*)\}|\[([^]]*)\]) 
        # and match a parameter in group 1 
    ) 
    /x', 
    $input, 
    $parameters); 
// again, you'll have an array of parameters in $parameters[1] 

Working demo.

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

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

+2

В PHP '' \\ a'' '' '' a ', чтобы получить' \\ a' вам нужно написать '' \\\\ a''.Или вы можете использовать '<<< 'quoting''. (Думаю.) :-p – Qtax

+0

@Qtax конечно:) ... спасибо, что заметили. fixed;) –

+0

Работает как шарм. Отлично, спасибо! – Mark

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