gpt4 book ai didi

string - "Simple String template replacement in Scala and Clojure"的后续

转载 作者:行者123 更新时间:2023-12-02 05:42:06 27 4
gpt4 key购买 nike

在我之前的post中,我展示了一个简单(朴素)的算法来进行字符串模板替换。

解决方案之一,由mikera提供,似乎是一个更好的算法。我在 Clojure 中实现了它(如下),并根据我之前的算法对其进行了计时。新的在 100 次运行中较慢(41.475 毫秒 vs. 19.128 毫秒)。我一定在我的新实现中做了一些愚蠢的事情。

(defn replace-templates
"Return a String with each occurrence of a substring of the form {key}
replaced with the corresponding value from a map parameter.
@param str the String in which to do the replacements
@param m a map of keyword->value"
[text m]
(let [builder (StringBuilder.)
text-length (.length text)]
(loop [current-index 0]
(if (>= current-index text-length)
(.toString builder)
(let [open-brace (.indexOf text "{" current-index)]
(if (< open-brace 0)
(.toString (.append builder (.substring text current-index)))
(let [close-brace (.indexOf text "}" open-brace)]
(if (< close-brace 0)
(.toString (.append builder (.substring text current-index)))
(do
(.append builder (.substring text current-index open-brace))
(.append builder (let [key (keyword (.substring text (inc open-brace) close-brace))
replacement (m key)]
(if (nil? replacement) "" replacement)))
(recur (inc close-brace)))))))))))

尽管它通过了所有测试用例:

(use 'clojure.test)

(deftest test-replace-templates
(is (= (replace-templates "this is a test" {:foo "FOO"})
"this is a test"))
(is (= (replace-templates "this is a {foo} test" {:foo "FOO"})
"this is a FOO test"))
(is (= (replace-templates "this is a {foo} test {bar}" {:foo "FOO" :bar "BAR"})
"this is a FOO test BAR"))
(is (= (replace-templates "this is a {foo} test {bar} 42" {:foo "FOO" :bar "BAR"})
"this is a FOO test BAR 42"))
(is (= (replace-templates "this is a {foo} test {bar" {:foo "FOO" :bar "BAR"})
"this is a FOO test {bar")))

; user=> Ran 1 tests containing 5 assertions.
; user=> 0 failures, 0 errors.
; user=> {:type :summary, :test 1, :pass 5, :fail 0, :error 0}

这是测试代码:

(time (dotimes [n 100] (replace-templates
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
elit nisi, egestas et tincidunt eget, {foo} mattis non erat. Aenean ut
elit in odio vehicula facilisis. Vestibulum quis elit vel nulla
interdum facilisis ut eu sapien. Nullam cursus fermentum
sollicitudin. Donec non congue augue. {bar} Vestibulum et magna quis
arcu ultricies consectetur auctor vitae urna. Fusce hendrerit
facilisis volutpat. Ut lectus augue, mattis {baz} venenatis {foo}
lobortis sed, varius eu massa. Ut sit amet nunc quis velit hendrerit
bibendum in eget nibh. Cras blandit nibh in odio suscipit eget aliquet
tortor placerat. In tempor ullamcorper mi. Quisque egestas, metus eu
venenatis pulvinar, sem urna blandit mi, in lobortis augue sem ut
dolor. Sed in {bar} neque sapien, vitae lacinia arcu. Phasellus mollis
blandit commodo." {:foo "HELLO" :bar "GOODBYE" :baz "FORTY-TWO"})))

; user=> "Elapsed time: 41.475 msecs"
; user=> nil

我想知道问题是否是StringBuilder的不断重新分配。

最佳答案

我认为你受到了反射(reflection)的打击。 *warn-on-reflection* 是你的 friend 。这里有一些测试 criterium .

replace-templates-original:         56.4us
replace-templates-original-hinted: 9.4us
replace-templates-new: 131.4us
replace-templates-new-hinted: 6.3us
replace-templates-very-new: 7.3us

这是replace-templates-very-new,这是我自己为高尔夫制作的版本。 :)

(defn replace-templates-very-new
[^String text m]
(let [builder (StringBuilder.)]
(loop [text text]
(cond
(zero? (count text))
(.toString builder)

(.startsWith text "{")
(let [brace (.indexOf text "}")]
(if (neg? brace)
(.toString (.append builder text))
(do
(.append builder (get m (keyword (subs text 1 brace))))
(recur (subs text (inc brace))))))

:else
(let [brace (.indexOf text "{")]
(if (neg? brace)
(.toString (.append builder text))
(do
(.append builder (subs text 0 brace))
(recur (subs text brace)))))))))

它通过了所有测试,所以它应该可以工作。

更新:支持非键大括号括起来的值 ("this is a {not-a-key-{foo}-in-the-map} test"=> "this是一个 {not-a-key-FOO-in-the-map} 测试"),允许它在 Java 代码生成器中使用,其中非键大括号括起来的内容很重要:-)。

(defn replace-templates-even-newer
"Return a String with each occurrence of a substring of the form {key}
replaced with the corresponding value from a map parameter.
@param str the String in which to do the replacements
@param m a map of keyword->value
@thanks kotarak http://stackoverflow.com/questions/6112534/
follow-up-to-simple-string-template-replacement-in-scala-and-clojure"
[^String text m]
(let [builder (StringBuilder.)]
(loop [text text]
(cond
(zero? (count text))
(.toString builder)

(.startsWith text "{")
(let [brace (.indexOf text "}")]
(if (neg? brace)
(.toString (.append builder text))
(if-let [[_ replacement] (find m (keyword (subs text 1 brace)))]
(do
(.append builder replacement)
(recur (subs text (inc brace))))
(do
(.append builder "{")
(recur (subs text 1))))))

:else
(let [brace (.indexOf text "{")]
(if (neg? brace)
(.toString (.append builder text))
(do
(.append builder (subs text 0 brace))
(recur (subs text brace)))))))))

关于string - "Simple String template replacement in Scala and Clojure"的后续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6112534/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com