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 正则表达式字面量是一个编译时构造的 read-time 结构,编译为运行时 Pattern 对象(我猜是一种状态机)。该编译对象的 behav删除 ior 来自字符串以及模式编译时的标志。模式对象在 Java 中具有身份语义。Clojure 在这里遵循主机的情况。

我们觉得没有理由假装可以比较正则表达式作为值。这很久以前就被考虑并决定了。

创建自己的 deftype,它封装正则表达式模式并实现任何所需的等价性语义相对容易。
...