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个正则表达式编译保存是非常必要的,否则对6,000个字符串进行`re-find`会花费21秒,而不是9.5秒。如果我`(memoize re-pattern)`,时间将会是26秒。

没有正则表达式相等性,至少基于它们创建的字符串,也会让编写测试变得非常痛苦。

一方面,正则表达式在Clojure中就像是一等公民,它们甚至有自己的内建字面表示法,可以用作哈希表键,但是在等价性方面却遇到了问题。

如果从相同的字符串编译出了 `java.util.regex.Pattern`,生成的对象将以相同的方式表现,因此可以认为它们是相等的。

我看不出不同正则字符串可能产生相同的匹配行为与这个问题有什么相关。我们谈论的是 `=` 运算符,而不是`does-it-behave-the-same?` 运算符... :/

检测正则对象实例是否与另一个相同有什么用例吗?
Clojure正则表达式字面量是一个读取时构造,编译成运行时的Pattern对象(我猜想是一种某种状态机)。这个编译对象的行 为由字符串和模式编译时使用的标志共同决定。Pattern对象在Java中有身份语义。Clojure遵循宿主的这种做法。

我们不认为假装能将正则表达式作为值进行比较是有意义的。这很久以前已经考虑过并决定了。

创建一个包装正则模式的自己的deftype并实现你想要的任何等价语义相对容易。
...