0

我正在尝试制作一个简单的 Lexer 来了解它们是如何工作的。我正在尝试找出一个可以捕获任何类型的打开 HTML 标记的良好 POSIX 字符串。我做了一个几乎可以工作但在更复杂的标签(如元标签等)上失败了。到目前为止,这就是我所拥有的:

"<\\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 的工作原理。

4

2 回答 2

3

除引号外的任何内容

对于属性的值,正确的扫描方法是匹配任何不是引号的内容。仅该部分的正则表达式如下所示:

    \"[^\"]*\"

我不知道你为什么有\"*;引号不能重复。还有其他问题,例如在任何可能的地方都允许空格或除了双引号之外还接受单引号(name='value'是 的替代方案name="value")。但是有一个更大的问题,所以我不会挑剔。

超出词法分析器

一个更重要的问题是你在你的词法分析器中塞进了太多的解析。词法分析器的工作是将字符流转换为标记流。标记是文本中不可分割的小单元。我不会尝试将整个开始标记、元素名称、属性等解析为单个标记。

相反,您应该撬出标签的较小部分:左尖括号、标识符、标识符、等号、字符串、右尖括号。让词法分析器识别这些片段并将其留给解析器以找出按该顺序排列的那些标记构成元素标记。

于 2010-12-09T04:23:24.837 回答
1

在您的 POSIX 字符串"<\\p{Alnum}+(\\p{Space}\\p{Alnum}+\\p{Space}*=\"*\\p{Space}*\\p{Alnum}+\"*)*\\p{Space}*>"中,您似乎没有照顾hyphenhttp-equiv

编辑 一个非常粗略的正则表达式可以写成如下:

"</?\\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 节点。

希望这会有所帮助。

于 2010-12-09T04:29:18.037 回答