{{clojure.string/split}} 限制分片功能无法按以下方式正确地分割字符串
(clojure.string/split "quaqb" #"q(?!u)") ; <- 匹配一个不在 'u' 后面的 'q'
;;=> ["qua" "b"]
(clojure.string/split "quaqb" #"q(?!u)" 2)
;;=> ["" "uaqb"]
第一种情况的结果是我们想要的,但第二种情况的结果是错误的。
这是因为,如果有限制,它会使用自己的函数来分割字符串,而不是使用 JavaScript 的 {{String.prototype.split}} 函数。
并且在这个正则表达式中使用 [前瞻或后顾](https://regexper.cn/lookaround.html) 时,该例程存在一个问题。
;; clojure.string/split
(let [re #"q(?!u)"]
(loop [s "quaqb"
limit 2
parts []]
(if (== 1 limit)
(conj parts s)
(let [m (re-find re s)] ; <- 1!
(if-not (nil? m)
(let [index (.indexOf s m)] ; <- 2!
(recur (.substring s (+ index (count m)))
(dec limit)
(conj parts (.substring s 0 index))))
(conj parts s))))))
;;=> ["" "uaqb"]
(re-find #"q(?!u)" "quaqb") ; <- 1!
;; => "q"
(.indexOf "quaqb" "q") ; <- 2!
;;=> 0
我们应该从 JavaScript 的 {{RegExp.prototype.exec}} 函数获取索引,而不是计算一个索引。
;; clojure.string/split
(let [re #"q(?!u)"]
(loop [s "quaqb"
limit 2
parts []]
(if (== 1 limit)
(conj parts s)
(let [m (.exec re s)]
(if-not (nil? m)
(let [index (.-index m)]
(recur (.substring s (+ index (count (aget m 0))))
(dec limit)
(conj parts (.substring s 0 index))))
(conj parts s))))))
;;=> ["qua" "b"]
i 在 V8、Spidermonkey 和 Nashorn 上进行了测试。