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 中更改这一点。出于性能和哲学 reasons(基于值的等价性),没有基于协议的方式扩展等价抽象,我认为我们永远不会添加这一点。

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

头像:
另一种选择是调用(.pattern #"some|regex"),这将返回底层字符串并比较这些字符串。
头像:
在“使用时”转换也是一种性能开销,因为`re-pattern`会进行正则表达式编译,这应该只发生一次,尤其是在重用正则表达式时。

目前我的用例是通过大约18000条正则表达式到类别映射的精选列表来分类字符串流,这些映射很少改变。

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

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

一方面,正则表达式在Clojure中感觉像第一类公民,因为它们甚至有内建的文本语法,可以用作哈希表键,但当涉及到等价性时,它们就崩溃了。

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

我实在不明白为什么不同的正则表达式字符串可能会产生相同的匹配行为。我们谈论的是`=`操作符,而不是`是否表现出相同的行为`操作符... :/

检测正则表达式对象实例是否与其他实例相同的用例是什么?
头像:
Clojure正则表达式文法是一个编译时刻的结构,它编译成运行时的Pattern对象(我猜是一种状态机)。该编译对象的操作行为来自字符串和编译模式时的标志。在Java中,模式对象有唯一性语义。Clojure遵循主机在这里的领导。

我们不觉得比较正则表达式作为值的做法是有意义的。这早就已经考虑并决定了。

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