В моем предыдущем посте я показал простой (наивный) алгоритм для замены шаблона String.
Одно из решений, предоставленных mikera ,Похоже, гораздо лучший алгоритм.Я реализовал это в Clojure (следует) и сравнил его с моим предыдущим алгоритмом.Новый на 10096 * медленнее (41,475 мсек против 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
.