在elisp中寻找替换字符串函数

时间:2013-06-26 16:35:24

标签: emacs elisp

我正在寻找只使用文字字符串,没有正则表达式的等效replace-regexp-in-string

(replace-regexp-in-string "." "bar" "foo.buzz") => "barbarbarbarbarbarbarbar"

但我想要

(replace-in-string "." "bar" "foo.buzz") => "foobarbuzz"

我尝试了各种replace-*函数,但无法弄明白。

修改

作为对精心设计的答案的回报,我决定对它们进行基准测试(是的,我知道所有基准测试都是错误的,但它仍然很有趣)。

benchmark-run的输出为(time, # garbage collections, GC time)

(benchmark-run 10000
  (replace-regexp-in-string "." "bar" "foo.buzz"))

  => (0.5530160000000001 7 0.4121459999999999)

(benchmark-run 10000
  (haxe-replace-string "." "bar" "foo.buzz"))

  => (5.301392 68 3.851943000000009)

(benchmark-run 10000
  (replace-string-in-string "." "bar" "foo.buzz"))

  => (1.429293 5 0.29774799999999857)

用引用的regexp获胜替换-regexp-in-string。临时缓冲区做得非常好。

修改2

现在有了汇编!不得不再做10倍的迭代:

(benchmark-run 100000
  (haxe-replace-string "." "bar" "foo.buzz"))

  => (0.8736970000000001 14 0.47306700000000035)

(benchmark-run 100000
  (replace-in-string "." "bar" "foo.buzz"))

  => (1.25983 29 0.9721819999999983)

(benchmark-run 100000
  (replace-string-in-string "." "bar" "foo.buzz"))

  => (11.877136 86 3.1208540000000013)

haxe-replace-string看起来不错

5 个答案:

答案 0 :(得分:20)

试试这个:

(defun replace-in-string (what with in)
  (replace-regexp-in-string (regexp-quote what) with in nil 'literal))

答案 1 :(得分:11)

s.el字符串操作库具有s-replace函数:

(s-replace "." "bar" "foo.buzz") ;; => "foobarbuzz"

如果您使用Elisp中的字符串,我建议您从Emacs包管理器安装s.el

答案 2 :(得分:5)

Emacs 28.1(在撰写本文时仍在开发中)将此作为标准提供:

** New function 'string-replace'.
This function works along the line of 'replace-regexp-in-string', but
matching on strings instead of regexps, and does not change the global
match state.
(string-replace FROMSTRING TOSTRING INSTRING)

Replace FROMSTRING with TOSTRING in INSTRING each time it occurs.

(string-replace ".*" "BAR" "foo.*bar.*baz")
 ⇒ "fooBARbarBARbaz"

答案 3 :(得分:4)

我不希望这更快:

(defun haxe-replace-string (string string-a string-b)
  "Because there's no function in eLisp to do this."
  (loop for i from 0 upto
        (- (length string) (length string-a))
        for c = (aref string i)
        with alen = (length string-a)
        with result = nil
        with last = 0
        do (loop for j from i below (+ i alen)
                 do (unless
                        (char-equal
                         (aref string-a (- j i))
                         (aref string j))
                      (return))
                 finally
                 (setq result
                       (cons (substring string last (- j alen)) result)
                       i (1- j) last j))
        finally
        (return
         (if result 
             (mapconcat
              #'identity
              (reverse (cons (substring string last) result)) string-b)
           string))))

Becasue replace-regexp-in-string是一个原生函数,但你永远不会知道......不管怎样,我之前因某种原因写过这个,所以,如果你喜欢比较性能 - 欢迎你试试:)

另一个想法,使用临时缓冲区:

(defun replace-string-in-string (what with in)
  (with-temp-buffer
    (insert in)
    (beginning-of-buffer)
    (while (search-forward what nil t)
      (replace-match with nil t))
    (buffer-string)))

答案 4 :(得分:2)

如果准备好使用

s-replace很好,但是说您想在加载过程中尽早使用替换字符串功能,并且还没有加载或s.el需要所有这些。好吧,这是s-replaces.el的定义。如您所见,它没有依赖性,因此您可以使用它而无需其余s.el

(defun s-replace (old new s)
  "Replaces OLD with NEW in S."
  (declare (pure t) (side-effect-free t))
  (replace-regexp-in-string (regexp-quote old) new s t t))