Skip to content

Commit 3e14690

Browse files
andrewhrswannodette
authored andcommitted
CLJS-1304: Behavior of c.string/replace differs from Clojure
JavaScript own's `String.prototype.replace` knows how to do string replacement using functions, therefore is used as internal implementation. But the signature differs as the js version feeds the matched groups as variadic arguements to the replacement function. The solution here is to create a "function adapter" between the js replace and the replacement function. For cases where we have a single matching string without any subgroup, we pass it directly, without the wrapping vector.
1 parent 8b7177a commit 3e14690

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

src/main/cljs/clojure/string.cljs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@
2424
(-> (.replace s re-surrogate-pair "$2$1")
2525
(.. (split "") (reverse) (join ""))))
2626

27+
(defn- replace-all
28+
[s re replacement]
29+
(.replace s (js/RegExp. (.-source re) "g") replacement))
30+
31+
(defn- replace-with
32+
[f]
33+
(fn [& args]
34+
(let [matches (drop-last 2 args)]
35+
(if (= (count matches) 1)
36+
(f (first matches))
37+
(f (vec matches))))))
38+
2739
(defn replace
2840
"Replaces all instance of match with replacement in s.
2941
match/replacement can be:
@@ -36,7 +48,9 @@
3648
(.replace s (js/RegExp. (gstring/regExpEscape match) "g") replacement)
3749

3850
(instance? js/RegExp match)
39-
(.replace s (js/RegExp. (.-source match) "g") replacement)
51+
(if (string? replacement)
52+
(replace-all s match replacement)
53+
(replace-all s match (replace-with replacement)))
4054

4155
:else (throw (str "Invalid match arg: " match))))
4256

src/test/cljs/clojure/string_test.cljs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
(testing "Testing string replace"
1414
(is (= "faabar" (s/replace "foobar" \o \a)))
1515
(is (= "barbarbar" (s/replace "foobarfoo" "foo" "bar")))
16+
(is (= "foobarfoo" (s/replace "foobarfoo" #"ooo" s/upper-case)))
1617
(is (= "FOObarFOO" (s/replace "foobarfoo" #"foo" s/upper-case)))
17-
(is (= "barbar)foo" (s/replace "foo(bar)foo" "foo(" "bar"))))
18+
(is (= "barbar)foo" (s/replace "foo(bar)foo" "foo(" "bar")))
19+
(is (= "FOO-ObarFOO-O"
20+
(s/replace "foobarfoo" #"f(o)o" (fn [[m g1]] (s/upper-case (str m "-" g1)))))))
1821

1922
(testing "Testing string join"
2023
(is (= "" (s/join nil)))

0 commit comments

Comments
 (0)