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"),这将返回底层字符串并比较这些字符串。
by
“使用时转换”也会影响性能,因为`re-pattern`执行正则表达式编译,这应该只发生一次,尤其是在重复使用正则表达式时。

我的当前用例是通过 curated list of ~18000 个 regex-to-category mappings 将字符串流分类,这些映射不经常变化。

非常希望能保持这 18000 个正则表达式编译,否则对约 6000 个字符串进行 `re-find` 操作将花费 21 秒而不是 9.5 秒。如果我对 `(memoize re-pattern)` 进行操作,则耗时 26 秒。

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

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

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

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

检测一个正则对象实例是否与另一个实例相同有何用例?
by
Clojure 正则表达式字面量是一个读取时构建,它编译为运行时 Pattern 对象(我假设是一种状态机)。这个编译后对象的行为既来源于字符串,也来源于在模式编译时使用的标志。模式对象在 Java 中具有唯一语义。Clojure 在这里遵循主机。

我们不认为将正则表达式作为值来比较是有意义的。这早就被考虑并决定了。

创建自己的 deftype 来封装正则表达式模式并实现您想要的任何相等语义是相对容易的。
...