我正在为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>
它可以匹配attr
,data-attr
和data-foo
,以及<
和div
类似的东西(这非常粗糙):
(<)([a-zA-Z0-9:.]+)(?:\s(?:([0-9a-zA-Z_-]*=?))\s?)*)[^/>]*(>)
它不需要是完美的,只是为了一些语法高亮,但我很难弄清楚如何在标签内实现多个捕获组,无论我是否应该使用环视等,或者用单个表达式是否可以实现这一点。
修改:以下是有关具体案例/问题的更多详细信息 - https://github.com/reactjs/sublime-react/issues/18
答案 0 :(得分:0)
我可能找到了一个可能的解决方案。
这并不完美,因为@skamazin在评论中说如果你试图捕获任意数量的属性,你将不得不重复与属性匹配的模式,因为你想要限制你的属性数量将允许。
正则表达式非常可怕但它可能适合您的目标。也许有可能简化它或者你可能需要调整一些事情
对于只有一个属性,它将如下:
(<)([a-zA-Z0-9:.]+)(?:(?: ((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))
要获得更多属性,您需要根据需要多次添加:
(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))?
例如,如果你想允许最多3个属性你的正则表达式将是这样的:
(<)([a-zA-Z0-9:.]+)(?:(?: ((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)(?: |>))(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)?(?: |>))?(?:(?:((?<= )[^ ]+?(?==| |>)))(?:=[^ >]+)?(?: |>))?
告诉我它是否适合您,以及是否需要进一步的细节。
答案 1 :(得分:0)
我不熟悉sublimetext或react-jsx,但这对我来说听起来像&#34;正则表达式是你的工具,而不是你的解决方案。&#34;
使用正则表达式作为工具的解决方案将是 like this JsFiddle (请注意,由于html实体(例如>
),正则表达式略有模糊处理对于>
等。)
执行实际替换的代码:
blabla.replace(/(<!--(?:[^-]|-(?!->))*-->)|(<(?:(?!>).)+>)|(\{[^\}]+\})/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个捕获组:
你可以看到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/
希望这有帮助!