HTML Lexer на Java - PullRequest
       37

HTML Lexer на Java

0 голосов
/ 09 декабря 2010

Я пытаюсь сделать простой Lexer, чтобы понять, как они работают. Я пытаюсь выяснить хорошую строку POSIX, которая может поймать открытие тегов HTML любого типа. Я сделал один, который почти работал, но не работает на более сложных тегах, таких как мета-теги и тому подобное. Пока это то, что у меня есть:

"<\\p{Alnum}+(\\p{Space}\\p{Alnum}+\\p{Space}*=\"*\\p{Space}*\\p{Alnum}+\"*)*\\p{Space}*>"

Эта строка POSIX ловит много тегов, но пропускает некоторые, такие как мета-теги и теги DOC. Вот тег, на котором произошел сбой:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Любая помощь будет высоко ценится. Я знаю, что это не лучший способ сделать Lexer, но это просто, чтобы помочь мне понять, как работает Regex.

Ответы [ 2 ]

3 голосов
/ 09 декабря 2010

Все, кроме кавычек

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

    \"[^\"]*\"

Я не уверен, почему у вас есть \"*;цитаты не могут быть повторены.Существуют и другие проблемы, такие как разрешение пробелов везде, где это возможно, или принятие одинарных кавычек в дополнение к двойным кавычкам (name='value' является альтернативой name="value").Но есть более серьезная проблема, поэтому я не буду придираться.

Превышение лексера

Более важной проблемой является то, что вы слишком много разбираете в своем лексере.Задача лексера - превратить поток символов в поток токенов.Токены - это небольшие неделимые единицы в тексте.Я бы не пытался анализировать весь открывающий тег, имя элемента, атрибуты и все как один токен.

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

1 голос
/ 09 декабря 2010

В вашей строке POSIX "<\\p{Alnum}+(\\p{Space}\\p{Alnum}+\\p{Space}*=\"*\\p{Space}*\\p{Alnum}+\"*)*\\p{Space}*>" кажется, что вы не заботитесь о hyphen в http-equiv

EDIT Очень грубое регулярное выражение можно записать следующим образом:

"</?\\w+((\\s+(\\w|\\w[\\w-]*\\w)(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?>"

Таким образом, для ввода, как это:

<html>
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   </head>
   <body>
     <h4>Test Page</h4>
   </body>
</html>

Выход будет:

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <h4>
    </h4>
  </body>
</html>

Будьте осторожны, если вы используете вышеприведенное регулярное выражение в качестве инструкций обработки, узлы CDATA и #Text не учитываются.

Надеюсь, это поможет.

...