HTML标记中语法突出显示属性的正则表达式

时间:2014-08-04 14:30:59

标签: regex sublimetext2 syntax-highlighting react-jsx

我正在为Sublime / TextMate语言文件中的一些语法高亮处理正则表达式,它要求我在非自我关闭的html标记上“开始”,并在相应的结束标记上结束:

  • 开始:(<)([a-zA-Z0-9:.]+)[^/>]*(>)

  • 结束:(</)(\2)([^>]*>)

到目前为止,非常好,我能够捕获标记名称,并且匹配能够为标记之间的区域应用适当的模式。

jsx-tag-area:
    begin: (<)([a-zA-Z0-9:.]+)[^/>]*>
    beginCaptures:
      '1': {name: punctuation.definition.tag.begin.jsx}
      '2': {name: entity.name.tag.jsx}
    end: (</)(\2)([^>]*>)
    endCaptures:
      '1': {name: punctuation.definition.tag.begin.jsx}
      '2': {name: entity.name.tag.jsx}
      '3': {name: punctuation.definition.tag.end.jsx}
    name: jsx.tag-area.jsx
    patterns:
    - {include: '#jsx'}
    - {include: '#jsx-evaluated-code'}

现在我也希望能够在开始标记中捕获零个或多个html属性以突出显示它们。

所以如果标签是<div attr="Something" data-attr="test" data-foo>

它可以匹配attrdata-attrdata-foo,以及<div

类似的东西(这非常粗糙):

(<)([a-zA-Z0-9:.]+)(?:\s(?:([0-9a-zA-Z_-]*=?))\s?)*)[^/>]*(>)

它不需要是完美的,只是为了一些语法高亮,但我很难弄清楚如何在标签内实现多个捕获组,无论我是否应该使用环视等,或者用单个表达式是否可以实现这一点。

修改:以下是有关具体案例/问题的更多详细信息 - https://github.com/reactjs/sublime-react/issues/18

4 个答案:

答案 0 :(得分:0)

我可能找到了一个可能的解决方案。

这并不完美,因为@skamazin在评论中说如果你试图捕获任意数量的属性,你将不得不重复与属性匹配的模式,因为你想要限制你的属性数量将允许。

正则表达式非常可怕但它可能适合您的目标。也许有可能简化它或者你可能需要调整一些事情

对于只有一个属性,它将如下:

(<)([a-zA-Z0-9:.]+)(?:(?: ((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))

DEMO

要获得更多属性,您需要根据需要多次添加:

(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))?

例如,如果你想允许最多3个属性你的正则表达式将是这样的:

(<)([a-zA-Z0-9:.]+)(?:(?: ((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)?(?: |>))?(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)?(?: |>))?

DEMO

告诉我它是否适合您,以及是否需要进一步的细节。

答案 1 :(得分:0)

我不熟悉sublimetext或react-jsx,但这对我来说听起来像&#34;正则表达式是你的工具,而不是你的解决方案。&#34;

使用正则表达式作为工具的解决方案将是 like this JsFiddle (请注意,由于html实体(例如&gt;),正则表达式略有模糊处理对于>等。)

执行实际替换的代码:

blabla.replace(/(&lt;!--(?:[^-]|-(?!-&gt;))*--&gt;)|(&lt;(?:(?!&gt;).)+&gt;)|(\{[^\}]+\})/g, function(m, c, t, a) {
    if (c!=undefined)
        return '<span class="comment">' + c + '</span>';
    if (t!=undefined)
        return '<span class="tag">' + t.replace(/ [a-z_-]+=?/ig, '<span class="attr">$&</span>') + '</span>';
    if (a!=undefined)
        return a.replace(/'[^']+'/g, '<span class="quoted">$&</span>');
});

所以在这里我首先捕获 this general pattern 之后的单独类型的组,以适应这种带有accolade-blocks的HTML用例。这些捕获被提供给一个函数,该函数确定我们正在处理的捕获类型,并使用自己的.replace()语句进一步替换此捕获中的子组。

真的没有其他可靠的方法可以做到这一点。我无法告诉你这是如何转化为你的环境的,但也许这有帮助。

答案 2 :(得分:0)

单独使用正则表达式似乎不够好,但由于您在这里使用了sublime的脚本,因此有一种方法可以简化代码和流程。请记住,我是一个vim用户,并不熟悉sublime的内部 - 同样,我通常使用javascript正则表达式,而不是PCRE(这似乎是sublime使用的格式,或最接近的格式)。

这个想法如下:

  • 使用正则表达式来获取标记,属性(在字符串中)和标记内容
  • 如有必要,使用捕获组进行进一步处理和匹配

在这种情况下,我制作了这个正则表达式:

<([a-z]+)\ ?([a-z]+=\".*?\"\ ?)?>([.\n\sa-z]*)(<\/\1>)?

首先找到一个开始标记,为标记名称创建一个控制组,如果它找到了一个空格,则匹配大量属性(在我可以使用的\"...\"模式内{{1}仅匹配非引号字符,但我有目的地匹配任何字符,直到结束引号 -​​ 这是为了匹配大部分属性,我们可以稍后处理),匹配标签之间的任何文本,然后最终匹配结束标签

它创建了4个捕获组:

  1. 标记名称
  2. 属性字符串
  3. 标记内容
  4. 结束标记
  5. 你可以看到in this demo,如果没有结束标记,我们就没有它的捕获组,属性相同,但我们总是得到一个捕获组的内容标签。这通常是一个问题(因为我们不能假设捕获的特征将在同一个组中),但它不在这里,因为在冲突的情况下,我们没有得到任何属性和内容,因此第二个捕获组是空的,我们可以假设它意味着没有属性,缺少第三组也说明了一切。如果没有什么要解析的话,任何东西都不能被错误地解析。

    现在要解析属性,我们可以简单地使用:

    \"[^\"]*?\"

    demo here。这给了我们完全属性。如果sublime的脚本可以让你做到这一点,它肯定会允许你在必要时进一步处理。你当然可以使用这样的东西:

    ([a-z]+=\"[^\"]*?\")

    将分别为属性及其名称和值提供捕获组。

    使用这种方法,您应该能够足够好地解析标签,以便在2-3次通过中突出显示,并将内容发送到您想要的任何荧光笔(或者只是以任何您想要的方式突出显示为纯文本)

答案 3 :(得分:0)

你自己的正则表达式在回答你的问题时非常有帮助。

这似乎对我很有用:

/(:?<|<\/)([a-zA-Z0-9:.]+)(?:\s(?:([0-9a-zA-Z_-]*=?))\s?)*[^/>]*(:?>|\/>)/g

开头和结尾的/只是正则表达式通常需要的包装器。另外,最后的g代表全局,所以它也适用于重复。

我用来判断我的正则表达式错误的一个好工具是:http://regexr.com/

希望这有帮助!