请在 2024 Clojure 状态调查 中分享您的想法!

欢迎来到!请查看 关于 页面以获得更多有关如何操作的信息。

+2
ClojureScript
编辑

你好,

我在 ClojureScript 从 Clojure 中看到 re-seq 有这个差异

;; CLJ
(re-seq #"^[a-f]" "aabcded") ;; => ("a")

;; CLJS
(re-seq #"^[a-f]" "aabcded") ;; => ("a" "a" "b" "c" "d" "e" "d")

这是 bug 吗?

ClojureScript 版本 1.10.520

(登录为 https://clojure.atlassian.net/browse/CLJS-3187)

4 个答案

0
 
最佳答案

由 Alex Miller 记录为在此处为 bug:https://clojure.atlassian.net/browse/CLJS-3187

+3

这是 ClojureScript 中 re-seq 实现的 bug。

(defn re-seq
  "Returns a lazy sequence of successive matches of re in s."
  [re s]
  (let [match-data (re-find re s)
        match-idx (.search s re)
        match-str (if (coll? match-data) (first match-data) match-data)
        post-idx (+ match-idx (max 1 (count match-str)))
        post-match (subs s post-idx)]
    (when match-data (lazy-seq (cons match-data (when (<= post-idx (count s)) (re-seq re post-match)))))))

问题出现在它重复地将字符串的余下部分递归到 re-seq 中。这样做意味着 ^[a-f] 将再次匹配这个新的、较短的字符串。

一个解决方案是使你的正则表达式具有粘性。

(js/RegExp. #"^." "y")

这会使后续使用正则表达式时意识到之前的匹配。请注意,你需要小心放置此代码,因为它需要在正确的位置创建,不能是全局的!如果它是全局的,就会遇到像这样的奇怪状态问题

(let [re (js/RegExp. #"^." "y")]
  [(re-seq re "cccc")
   (re-seq re "abbb")])
;; => [("c" "c") nil]

(我根本无法解释!)

re-seq 的另一种实现可能为你创建这个初始副本

(defn re-seq2
  "Returns a lazy sequence of successive matches of re in s."
  [re s]
  (let [re-seq* (fn re-seq* [re s]
                  (let [match-data (re-find re s)
                        match-idx (.search s re)
                        match-str (if (coll? match-data) (first match-data) match-data)
                        post-idx (+ match-idx (max 1 (count match-str)))
                        post-match (subs s post-idx)]
                    (when match-data (lazy-seq (cons match-data (when (<= post-idx (count s)) (re-seq* re post-match)))))))]
    (re-seq* (js/RegExp. re "y") s)))

(let [re #"^."]
  [(re-seq2 re "cccc")
   (re-seq2 re "abbb")])
;; => [("c") ("a")]
恭喜你找到了解决所提出问题的方案。

不幸的是,粘性似乎会破坏 re-seq,使其与其他表达式与 CLJ 保持一致。

;; CLJ
(re-seq #"[a-f]" "aabcded")
;; => ("a" "a" "b" "c" "d" "e" "d")

;; CLJS (sticky)
(re-seq (js/RegExp. #"[a-f]" "y") "aabcded")
;; => ("a" "b" "e")

;; CLJS (re-seq2)
(re-seq2 #"[a-f]" "aabcded")
;; => ("a" "b" "d" "d")
0

FWIW,我最终通过以下方式重新实现了 re-seq 来解决这个问题

(defn re-seq [re s]
  (let [re* (js/RegExp. re "g")
        xf (comp (take-while some?)
                 (map first))]
    (sequence xf (repeatedly #(.exec re* s)))))

一旦 lazy-seq 从方程中移除(并将正则表达式切换为“全局”),它就会按照我的测试用例正常运行。

0
by

我为Jira工单创建了一个补丁。
解决方案是在正则表达式中添加一个全局标志,如果还没有的话,然后反复调用RegExp.prototype.exec()方法,直到没有更多匹配为止。
如果您发现任何问题,请告诉我。

...