2024 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于 页面以了解更多关于此如何工作的信息。

0
编译器

如何在嵌套结构中检查正则表达式等价性?

(= #"." #".") ;; #=> false
(= [#"."] [#"."]) ;; #=> false
(= ["."] ["."]) ;; #=> true

我相信正则表达式是一个值对象。
因此,如果两个正则表达式完全相等,则它们相等。

是否可以更新=函数以支持正则表达式等价性?

可能如下所示

(defprotocol IEquals
 (equals [a b]))

(extend-protocol IEquals
  Object
  (equals [a b] (.equals a b))
  
  Pattern
  (equals [a b]
    (and
      (instance? Pattern b)
      (= (str a) (str b))) 

并且 clojure.lang.Util.equiv 使用
IEquals#equals 而不是 Object#equals
但是我不知道如何从clojure.lang.Util调用协议方法。

1 个答案

+2

正则表达式模式具有标识等价性语义。我们已经充分讨论了这一点,Clojure中没有计划进行更改。出于性能和哲学(基于值的等价性)的原因,没有基于协议的方法来扩展等价性抽象,我认为我们永远也不会添加这一功能。

如果您想比较模式的等价性,一个选项是将您的正则表达式保留为字符串进行比较,然后在需要时使用 re-pattern 转换为正则表达式。

另一种选择可能是调用(.pattern #"some|regex"),这将返回底层字符串,然后比较这些字符串。
由于`re-pattern`会进行正则表达式编译,这会降低性能,因为编译只应发生一次,尤其是在重新使用正则表达式时。

我目前的用例是通过大约18000个正则表达式到类别的映射来对字符串流进行分类,这不太会改变。

非常希望将这些18000个正则表达式编译出来,否则对大约6000个字符串进行`re-find`操作需要21秒而不是9.5秒。如果我在`(memoize re-pattern)`中,则需要26秒。

如果没有正则表达式相等,至少基于它们创建的字符串,那么编写测试也相当痛苦。

一方面,正则表达式感觉像是Clojure的第一等公民,因为它们甚至有自己的内置字面量语法,可以用作哈希表键,但一旦涉及到相等时就会崩溃。

如果从同一字符串编译出`java.util.regex.Pattern`,则结果对象的行为方式将相同,因此可以认为它们是相等的。

我无法理解为什么不同的正则表达式字符串可能会产生相同的匹配行为。我们谈论的是`=`运算符,而不是`does-it-behave-the-same?`运算符... :/

检测正则表达式对象实例是否与另一个相同实例有什么用例呢?
Clojure正则表达式字面量是在读取时构造的,编译成运行时Pattern对象(我猜是一种状态机)。这个编译对象的操作来自于字符串和模式编译时使用的标志。Pattern对象在Java中具有标识语义。Clojure遵循宿主的这一做法。

我们认为将正则表达式作为值来比较并没有意义。这以前已经考虑过,并作出了决定。

创建自己的正则表达式模式包装器('[')类型,并实现你想要的任何等价语义相对简单。
...