2013-08-02 6 views
0

Я узнаю о регулярных выражениях и хочу написать механизм шаблонов в PHP.Регулярное выражение для шаблона?

Рассмотрим следующий "шаблон":

<!DOCTYPE html> 
<html lang="{{print("{hey}")}}" dir="{{$dir}}"> 
<head> 
    <meta charset="{{$charset}}"> 
</head> 
<body> 
    {{$body}} 
    {{}} 
</body> 
</html> 

мне удалось создать регулярное выражение, которое будет найти что-либо, за исключением {{}}.

Вот мое регулярное выражение:

{{[^}]+([^{])*}} 

Там только одна проблема. Как разрешить литерал { и } для использования в пределах {{}} тегов?

Он не найдет {{print("{hey}")}}.

Заранее спасибо.

+0

Просто введением в HTML и Regex: http://stackoverflow.com/a/1732454/758446 – BlackVegetable

+0

Вы можете использовать общий placeholder вместо отрицательного charclass для исключения '{' и '}' внутри. – mario

+0

Как мы все знаем, регулярные выражения чрезвычайно медленны, особенно когда речь идет о больших строках. В вашем случае вы можете просто придерживаться 'str_replace()', и это будет достаточно для вас. – Yang

ответ

2

Это шаблон, чтобы соответствовать содержанию внутри двойных фигурных скобках:

$pattern = <<<'LOD' 
~ 
(?(DEFINE) 
    (?<quoted> 
     ' (?: [^'\\]+ | (?:\\.)+)++ ' | 
     " (?: [^"\\]+ | (?:\\.)+)++ " 
    ) 
    (?<nested> 
     { (?: [^"'{}]+ | \g<quoted> | \g<nested>)*+ } 
    ) 
) 

{{ 
    (?<content> 
     (?: 
      [^"'{}]+ 
      | \g<quoted> 
      | \g<nested> 

     )*+ 
    ) 
}} 
~xs 
LOD; 

Компактная версия:

$pattern = '~{{((?>[^"\'{}]+|((["\'])(?:[^"\'\\\]+|(?:\\.)+|(?:(?!\3)["\'])+)++\3)|({(?:[^"\'{}]+|\g<2>|(?4))*+}))*+)}}~s'; 

Содержимое находится в первой группе захвата, но вы можете использовать именованный захват 'content' с подробной версией.

Если этот шаблон длиннее, он позволяет использовать все, что вы хотите, внутри цитируемых частей, включая экранированные кавычки, и во многих случаях быстрее, чем простой ленивый квантификатор. Вложенные фигурные скобки также разрешены, вы можете написать {{ doThat(){ doThis(){ }}}} без проблем.

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

(["'])    # the quote type is captured (single or double) 
(?:    # open a group (for the various alternatives) 
    [^"'\\]+  # all characters that are not a quote or a backslash 
    |    # OR 
    (?:\\.)+  # escaped characters (with the \s modifier) 
    |    # 
    (?!\g{-1})["'] # a quote that is not the captured quote 
)++    # repeat one or more times 
\g{-1}    # the captured quote (-1 refers to the last capturing group) 

Примечание: обратная косая черта должна быть написана \\ в синтаксис nowdoc, но \\\ или \\\\ внутри одиночных кавычек.

Пояснения к детальным рисунком:

Картина разделена на две части:

  • определения, где я определяю по имени Подмаски
  • сама вся картина

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

Этот раздел содержит 2 именованных подшаблоны:

  • цитируемого: который содержит описание цитируемых частей
  • вложенной: который описывает вложенные фигурные скобки.

det Айыл вложенного

(?<nested>   # open the named group "nested" 
    {    # literal { 
## what can contain curly brackets? ## 
    (?>    # open an atomic* group 
     [^"'{}]+  # all characters one or more times, except "'{} 
     |    # OR 
     \g<quoted> # quoted content, to avoid curly brackets inside quoted parts 
        # (I call the subpattern I have defined before, instead of rewrite all) 
     | \g<nested> # OR curly parts. This is a recursion 
    )*+    # repeat the atomic group zero or more times (possessive *) 
    }    # literal } 
)     # close the named group 

(* Более подробная информация о atomic groups и possessive quantifiers)

Но все это суть лишь определения, картина начинается действительно с: {{ Затем я открываю именем захвата группы (content), и я описываю, что можно найти внутри, (здесь ничего нового).

Используется для модификаторов, x и s. x активирует подробный режим, который позволяет свободно помещать пробелы в шаблон (полезно для отступов). s - это режим одиночной линии. В этом режиме точка может соответствовать новым строкам (по умолчанию она не может быть). Я использую этот режим, потому что есть точка в подшаблоне quoted.

+0

Вау, я не понимаю, как это работает, но это так! Я пытался сделать это неудачно, но это не будет! спасибо :) –

+0

@PetterThowsen: что вы не понимаете? –

+0

хорошо, самый часть. Я очень новичок в регулярных выражениях: P –

0

Сделайте regex менее жадным, используя {{(.*?)}}.

2

Вы можете просто использовать «.». вместо классов символов. Но тогда вам нужно использовать нежирные кванторы:

\{\{(.+?)\}\} 

Квантификатор "+?" означает, что он будет потреблять наименее необходимое количество символов.

Рассмотрим следующий пример:

<table> 
    <tr> 
    <td>{{print("{first name}")}}</td><td>{{print("{last name}")}}</td> 
    </tr> 
</table> 

С жадным квантором (+ или *), вы можете получить только один результат, потому что он видит первый {{, а затем .+ потребляет столько символов, сколько он может до тех пор, как образец сопоставляется: (? + или *)

{{print("{first name}")}}</td><td>{{print("{last name}")}} 

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

{{print("{first name}")}} 
{{print("{last name}")}} 
+0

Я пробовал, он работает. Но что, если в шаблоне есть следующее? Он не найдет его правильно. –

+0

В этом случае regexp, вероятно, не подходит. Когда дело доходит до рекурсивных паттернов, быстрее и понятнее кодировать его вручную.Вы по очереди проходите через каждого персонажа. Когда вы сталкиваетесь с {{', вы начинаете« записывать »следующие символы, и вы используете счетчик« открытая скобка ». Счетчик увеличивается для каждого '(', уменьшается для каждого ')'. Когда вы встретите '}}' * и * счетчик равен нулю, вы закончите: у вас есть маркер вашего шаблона. – Pikrass

+0

Hm. это умно! возможно, я попробую это. –

0

Я понял. Не спрашивай меня, как.

{{[^{}]*("[^"]*"\))?(}}) 

Это будет соответствовать почти все .. как, например:

{{print("{{}}}{{{}}}}{}}{}{hey}}{}}}{}7")}} 
+0

Исключает, если ваш шаблон содержит любые кавычки типа '' –

+0

да. оно делает. он также терпит неудачу, если я это делаю '{{function() {}}}' –

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