2013-12-15 1 views
0

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

В настоящее время я работаю над lexer, который, как мне кажется, касается работы по преобразованию потока символов в токены. То, что я хочу сделать, - это захват определенных структур в документе HTML, который позже может быть обработан парсером.

Это пример синтаксиса:

<head> 

    <title>Template</title> 
    <meta charset="utf-8"> 

</head> 

<body> 

    <h1>{{title}}</h1> 

    <p>This is also being matched.</p> 

    {{#myName}} 
     <p>My name is {{myName}}</p> 
    {{/}} 

    <p>This content too.</p> 

    {{^myName}} 
     <p>I have on name.</p> 
    {{/}} 

    <p>No matching here...</p> 

</body> 

Я пытаюсь сканировать только все между начальной '{{' символов и заканчивая " }}' персонажи. Таким образом, {{title}} будет одним совпадением, а также {{#myName}}, текст и содержание, предшествующие {{/}}, это должно быть второе совпадение.

Я особо не лучший в регулярных выражениях, и я уверен, что это проблема с шаблоном я придумал, что это:

({{([#\^]?)([a-zA-Z0-9\._]+)}}([\w\W]+){{\/?}})

Я прочитал это как матч два { символов, то либо # или^любые слова, содержащие прописные или строчные буквы, а также любые цифры, точки или символы подчеркивания. Сопоставьте все, что приходит после закрытия}} символов, до тех пор, пока не будут выполнены символы {{/}}, но часть /}} не является обязательной.

Проблема видна по следующей ссылке. Это совпадающий текст, который не находится внутри блоков {{и}}. Мне интересно, что это связано с использованием \ w и \ W, потому что, если я конкретно укажу, какие символы я хочу сопоставить в наборе, он, похоже, работает.

Тест регулярного выражения - here. Я смотрел на регулярное выражение - это общий список для захвата всего текста, который не является HTML, и я заметил, что он использует lookaheads, которые я просто не могу понять, или понять, почему они мне помогут.

Может ли кто-нибудь помочь мне, указав проблему с регулярным выражением, или я не ошибаюсь в этом с точки зрения создания lexer?

Надеюсь, я предоставил достаточно информации и благодарю вас за любую помощь!

+0

Вы слишком много соответствуете. Вы должны просто преобразовать индивидуальные '{{things}}' в токены. Во-первых, ваш пример содержит вложенные '{{things}}' - безусловно, это не может быть один токен (и, конечно, регулярного выражения недостаточно для захвата такой структуры). Фактически, все, что со структурой должно происходить в грамматике, а не в лексере. – tripleee

+0

@tripleee Я намереваюсь это сделать, но сначала я хотел их захватить, а затем разбить их дальше, так как меня не интересует другой контент. – Mark

ответ

2

Ваш шаблон не работает, потому что [\w\W]+ принимает все возможные символы до последнего {{/}} вашей строки. Квантификаторы (то есть +, *, {1,3}, ?) являются жадными по умолчанию.Для того, чтобы получить ленивый квантор вы должны добавить ? после него: [\w\W]+?

шаблон для работы с вложенными структурами:

$pattern = <<<'LOD' 
~ 
{{ 
(?|     # branch reset group: the interest of this feature is that 
        # capturing group numbers are the same in all alternatives 
    ([\w.]++)}}  # self-closing tag: capturing group 1: tag name 
    |     # OR 
    ([#^][\w.]++)}} # opening tag:  capturing group 1: tag name 
    (    # capturing group 2: content 
     (?>   # atomic group: three possible content type 
      [^{]++ # all characters except { 
      |   # OR 
      {(?!{) # { not followed by another { 
      |   # OR 
      (?R)  # an other tag is met, attempt the whole pattern again 
     )*   # repeat the atomic group 0 or more times 
    )    # close the second capturing group 
    {{/}}   # closing tag 
)     # close the branch reset group 
~x 
LOD; 

preg_match_all($pattern, $html, $matches); 

var_dump($matches); 

Чтобы получить все вложенные уровни вы можете использовать этот шаблон:

$pattern = <<<'LOD' 
~ 
(?=(       # open a lookahead and the 1st capturing group 
    {{ 
    (?| 
     ([\w.]++)}} 
     | 
     ([#^][\w.]++)}} 
     (      # ?R was changed to ?1 because I don't want to 
     (?>[^{]++|{(?!{)|(?1))* # repeat the whole pattern but only the 
     )      # subpattern in the first capturing group 
     {{/}} 
    ) 
)        # close the 1st capturing group 
)        # and the lookahead 
~x 
LOD; 

preg_match_all($pattern, $html, $matches); 

var_dump($matches); 

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

Дополнительная информация о регулярных выражений функций, используемых в этих двух моделей:

  • possessive quantifiers++
  • atomic groups(?>..)
  • lookahead(?=..), (?!..)
  • branch reset group(?|..|..)
  • recursion(?R), (?1)
  • +0

    Спасибо. Я обязательно посмотрю на эти ресурсы. Для регулярных выражений достаточно много. – Mark