我们现在都知道,使用正则表达式解析HTML通常是不可能的,因为它将解析上下文敏感的语法,而正则表达式只能解析正则语法。对于其他编程语言来说也是如此。
最近,Rainbow.js语法高亮器已经发布。它的前提被描述得非常简单:
彩虹本身就很简单。它遍历代码块,处理正则表达式模式,并将匹配的模式 Package 在标记中。
我认为语法突出显示本质上是一个与语言解析相同复杂性的任务,如果我们假设它必须既好又适合许多语言的话。尽管有很多criticism的库,但无论是criticism还是HackerNews discussion(作为技术倾向讨论的示例)都没有提到使用正则表达式突出显示语法在一般情况下基本上是不可能的,我认为这是一个主要的,停止显示的缺陷。
现在的问题是我是不是漏掉了什么特别是:
1.一般情况下,正则表达式的语法高亮显示是可能的吗?
1.这是一个应用80/20规则的例子吗?正则表达式的用处就足够了。
4条答案
按热度按时间iyzzxitl1#
使用regexp突出显示语法是一种古老的技术。Emacs和vi也是这样开始的。
我认为语法突出显示本质上是一项与语言解析相同复杂性的任务,[...]
不。区别在于:编译器需要真实的的解析,因为它需要理解完整的程序,也需要从理解中生成东西。另一方面,语法突出显示不需要理解代码。它只需要理解语言的一般结构-什么是字符串字面量-什么是关键字...等等。这种差异的副作用是:您可以突出显示语法不正确的代码,但不能分析它。
一个稍微不同的方法:解析一种语言通常是一个两步的过程:词法分析(将字节流拆分为“令牌”流)和真实的的解析(将令牌流带入某种复杂的结构-通常是抽象语法树)。词法分析通常使用正则表达式来完成。请参阅Flex文档。这基本上是所有基本语法荧光笔需要了解。
当然,也有一些极端情况是regexp无法单独处理的。一个典型的例子是:
这里
foo
可能是对静态方法、示例方法、宏或其他东西的调用。但是你的正则表达式高亮器不能推断出这一点。它只能为“一般调用”添加颜色。所以:如果您的需求是低级别的(即:没有上面的例子),并且对于真实的世界的东西通常是90/10规则。
ar5n3qh52#
您可以使用正则表达式作为解决方案的一部分来进行语法高亮显示。更具体地说,作为“词法分析器”的一部分,将输入文本分块为符号。这实际上是大多数编译器/解释器的工作方式。
但是,单独使用regex * 来实现它是自找麻烦。考虑在Python中匹配字符串的情况。Python允许字符串用单引号
'
或双引号"
分隔。此外,它还允许使用三引号'''
或"""
的多行字符串(“heredoc语法”)。那么下面的哪些部分是字符串,哪些不是?你能构造一个正则表达式来正确识别字符串文字
str1
-str6
吗?“你不能(解析HTML|处理程序),因为(HTML|虽然“正则表达式(特别是Perl语言)具有嵌套结构--它们不是 * 正则 *”并不完全正确--但现代正则表达式(特别是Perl语言)比计算机科学意义上的严格 * 正则 * 表达式具有更强的表达能力。但是仅仅因为你可以使用正则表达式并不意味着你应该使用它。
编辑:如果你的regex flavor支持搜索模式中的反向引用,那么上面的字符串匹配问题就不会太糟糕。像
('|"|'''|""").+?\1
这样的多行正则表达式可能就可以了。编辑2:对于语法高亮中的极端情况的示例,只需查看上面代码的StackOverflow语法高亮即可。
kkih6yb83#
基本上,没有。
您需要一个能够理解语言的解析器/标记器来选择要突出显示的位。
Regex不适合这样的任务。
omtl5h9j4#
一个很好的例子是Vim中的语法高亮实现。它使用基于正则表达式的模式。然而,模式用于识别文档中的分层包含结构,而不是简单地将输入标记化。
您可以声明区域,这些区域开始和结束于正则表达式模式匹配(加上另一个有助于跳过中间材料的模式)。这些区域可以声明它们包含其他区域或简单模式。遏制可以是递归的。Vim解决了所有这些问题。所以它本质上是一种上下文无关的解析形式。
这种方法可以处理具有不同嵌入级别和不同词法属性的语言。
例如,我有一种语言,其中基本上有两组关键字(由于正在进行的域语言嵌入)。我编写的Vim语法突出显示规则可以正确识别上下文,并以不同的方式对关键字进行着色。请注意,这些关键字集之间存在一些重叠:同一个词在不同的语境下有不同的意思
有关此的示例,请参见:http://www.kylheku.com/cgit/txr/tree/genman.txr。如果搜索语法
(do
,您会发现一个示例是紫色的,另一个是绿色的。它们是不同的:一种是文本提取语言,另一种是嵌入式Lisp方言。Vim的语法突出显示功能非常强大,足以处理具有不同关键字集的语言混合。(是的,虽然这是通过Web提供的,但它实际上是一个Vim进程,负责语法突出显示。或者考虑像shell这样的东西,你可以有一个字符串文字类型语法,比如
"foo bar"
,但是在里面,你可以有一个命令替换,在里面你必须递归地识别和着色shell语法:"foo $(for x in *; do ...; done) bar"
。所以,仅仅使用正则表达式标记化是无法实现有用的、准确的语法高亮显示的,但是使用正则表达式进行分层解析可以做得很好。