在你的想法,请在2024 年 Clojure 状态调查!分享你的看法。

欢迎!有关此如何工作,请参阅关于页面以获取更多信息。

0
ClojureScript

re-matches 函数不具有正确的语义:它对字符串进行搜索(而不是匹配)并在字符串和匹配字符串不相等时返回 nil。这不同于真正的匹配,就像在模式开始和结束时插入 "^" 和 "$" 一样。

Clojure 示例

user=> (re-find #"0|[1-9][0-9]+|0[xX][0-9a-zA-Z]+" "0x1") "0" user=> (re-matches #"0|[1-9][0-9]+|0[xX][0-9a-zA-Z]+" "0x1") "0x1"

与 Clojurescript 比较

ClojureScript:cljs.user> (re-find #"0|[1-9][0-9]+|0[xX][0-9a-zA-Z]+" "0x1") "0" ClojureScript:cljs.user> (re-matches #"0|[1-9][0-9]+|0[xX][0-9a-zA-Z]+" "0x1") nil

这(之一)是 CLJS-775 的原因。

我并不完全确定在这里要做什么。我首先想到的是让 re-matches 检查其正则表达式输入的 -source 属性,用 "^$" 包装字符串,然后仔细地将所有标志复制到一个新的正则表达式。

问题
1. 有没有任何有效的模式在做这件事时不安全?例如,我们能否在前面放置 "^" 的位置?"^^abc$$" 好吗?
1. 如果 "^" 和 "$" 已经是模式的第一个和最后一个字符,我们能否避免克隆?
1. 如果有所涉及,多行模式对此有何影响?
1. regexinstance.lastIndex 是正则表达式实例(或在旧浏览器上!)的可变性的一部分,它在相同字符串上的多次 exec() 调用时用作字符串偏移量。我完全没有主意如果 re-* 获得设置了全局标志的正则表达式要怎么做。(顺便说一句,这是拒绝 CLJS-150 的一个非常好的理由:允许 clojure 接受全局标志会让正则表达式对象具有状态,并完全破坏 re-seq 等。)

4 个答案

0

评论由:favila 发表

我想提出一个相对激进的建议,该建议将:修复此问题以及 CLJS-810,使我们能够更好地解决 CLJS-485 CLJS-746 CLJS-794(clojure.string/replace 痛点),使我们能够在 JS 中的模式添加一些正则表达式值的美感,并通过对 re-* 函数实施更多功能使 clojurescript 的正则表达式处理更接近 clojure。

示例实现(非补丁)可以在以下 cljsfiddle 上找到: http://cljsfiddle.net/fiddle/favila.regexp

关键点

  1. 使用 re-pattern 创建一个模式对象,该对象提供了创建用于搜索(re-find)或精确匹配(re-matches)或重复搜索(re-seq, re-matcher + re-find)的正则表达式的函数。即使它们是相似的,但由于在 JavaScript 中每个都必须是一个不同的 RegExp 对象,所以这些都必须是不同的。re-find 和 re-matches 模式可以是可缓存的。所有这些都可以以懒加载的方式生成正则表达式。
  2. 正则表达式文法会输出这些模式对象而不是 RegExp 对象。
  3. 创建一个与当前未实现的 re-matcher 对应的匹配器对象。它结合了一个全局标志的 RegExp 对象、一个搜索字符串和一个完成标志。如果它保持最后一个匹配项(类似于 Java),ClojureScript 也可以实现 re-groups。
  4. 让 re-seq 使用匹配器对象,从而使用原生正则表达式提供的 .lastIndex 进行全局匹配。(它的实现不再需要在每次匹配后进行字符串切片。)
  5. 如果 re-find 被给定为模式而不是正则表达式对象,它将按原样使用它。这符合当前的行为。
  6. 如果 re-matches 被给定为正则表达式对象并且它不适合精确匹配,则从输入的正则表达式克隆一个新的正则表达式,并在其前后添加 ^ 和 $,并添加全局标志。(这种技术用于 clojure.string/replace 中,但用错了。)

有什么想法吗?

0
by

评论者:dnolen

这听起来很有趣,但我对互操作问题有些担忧。我认为人们会期待函数可以接受正则表达式以及模式。你在这里没有提到这个问题吗?

0
by

评论由:favila 发表

如果我的某些想法不是很明确,抱歉;这个话题我已经有一段时间没想过。

首先,指出一类正则表达式实际上是“纯”的:如果它们执行完整的字符串匹配(例如,以 ^ 开头并以 $ 结尾)并且全局标志设置为 false,那么它们的 lastIndex 总是看起来是 0。

互操作可能性

  • 模式和正则表达式可以相互创建,所以强制转换总是一个选项。例如,re-pattern 可以接受一个 RegExp 和一些其他(ClojureScript 特定)的函数可以将 Pattern 或 Matcher 强制转换为 RegExp。(或者也许 re-matcher 可以返回一个与 RegExp 兼容的对象——见下文。)
  • 给 cljs 的正则表达式:”纯”正则表达式可以直接使用,否则我们会创建一个模式和一个/或匹配器。(我不记得细节了,但 fiddle 应该涵盖了它们。)
  • 将模式用作 RegExp:模式可以公开 RegExp 实例的所有属性。如果模式是纯的,它可以实现 .test 和 .exec。.lastIndex 总是会为 0。不确定如何处理不纯净的模式:抛出异常,表现得像纯模式一样,或者返回一个新的对象?
  • 将匹配器用作 RegExp:匹配器可以精确地重复一个 RegExp 实例,甚至可能使用相同的原型。像 RegExp 一样使用它将修改对象并扰乱它的内部状态,但只要它始终一致地用作 RegExp 或一直用作 Matcher,这就不会成问题。备注
    **** 匹配器在 Java 中保存匹配的字符串。JavaScript 信任你总是提供相同的字符串(例如,在 while 循环中)。
    • Java的Matcher持有最后一个匹配结果(用于正则表达式组)。JavaScript的RegExp则没有。
      当lastIndex达到源字符串末尾时,JavaScript的RegExp会自动重置。Java的Matcher不会。
      Matcher必须是一个包装器,而不仅仅是正则表达式,因为这三个额外的状态位。
      re-matcher的返回值仅由re-find和re-groups的1个参数形式使用。
      re-seq可以在内部使用matcher,但因为它私有的,所以没有必要。
    • 应该实现Matcher的其他Java方法吗?
  • 传递给String.prototype.match、.replace、.search和.split的Pattern:我没有考虑过这一点。考虑因素
    **** 任何使用模式文字或re-pattern创建的object,并在这些String方法作为参数使用的是问题代码。如果它们使用clojure.string方法而不是String方法,这样的代码是可以的。
    • 这样的代码在Java Clojure中也是不可能的:只有 (.split s "pattern-str") 在java/clj和js/cljs中是相同的,并且它将在两个平台上都继续工作(在不带标志的情况下)。我们可能只需让人们修复这样的代码,因为它与平台相关,但我需要看看这有多普遍。
      修复此类代码的方法是:
      使用我们将提供的pattern->regexp转换函数。
      直接使用js/RegExp构建正则表达式。 使用clojure.string函数而不是String方法。这也具有在clj和cljs之间可移植的优势。
    • 我们可能可以对RegExp构造函数进行修补或者掺入String原型链以自动进行pattern->regexp转换,但这是一个暴力的解决方案。

请纠正我,但如果是在Clojure(Java)代码中,使用Pattern和Match方法或者直接与String方法一起使用的情况非常罕见。大多数情况下,它们被视为通过re-*和clojure.string/**使用的不可见对象。在cljs中按照相同风格编写的代码不受影响,并且我们可以将其他任何使用声明为与平台相关,并需要明确创建正则表达式(Matcher或Pattern不需要表现得像正则表达式)。这是我首选的跨平台交互方法,如果在RegExp.prototype.test、.exec和String.prototype.match、.replace、.search、.split中不使用太多的话。

0
参考:https://clojure.atlassian.net/browse/CLJS-776(由favila提交)
...