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

spi*_*ike 17 emacs elisp

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

(replace-regexp-in-string "." "bar" "foo.buzz") => "barbarbarbarbarbarbarbar"
Run Code Online (Sandbox Code Playgroud)

但我想要

(replace-in-string "." "bar" "foo.buzz") => "foobarbuzz"
Run Code Online (Sandbox Code Playgroud)

我尝试了各种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)
Run Code Online (Sandbox Code Playgroud)

replace-regexp-in-string with quoted regexp wins.临时缓冲区非常好.

编辑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)
Run Code Online (Sandbox Code Playgroud)

haxe-replace-string看起来不错

Tre*_*son 21

试试这个:

(defun replace-in-string (what with in)
  (replace-regexp-in-string (regexp-quote what) with in nil 'literal))
Run Code Online (Sandbox Code Playgroud)

  • 第二个到最后一个paren应该移到外面,但是否则这是有效的.这没有内置的?看起来好像被遗漏了这么奇怪的事情. (4认同)

Mir*_*lov 13

s.el字符串操作库有s-replace功能:

(s-replace "." "bar" "foo.buzz") ;; => "foobarbuzz"
Run Code Online (Sandbox Code Playgroud)

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

  • OP 要求的是单个函数,而不是整个字符串功能库。此外,这意味着安装额外的东西(这对某些人来说不太理想)。这是一个很好的答案,但我看不出为什么它“应该”成为公认的答案——其他答案也同样合适。 (3认同)

小智 5

我不希望这样做更快:

(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))))
Run Code Online (Sandbox Code Playgroud)

因为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)))
Run Code Online (Sandbox Code Playgroud)


Joe*_*Joe 5

s-replace如果您准备好需要它,但是假设您想在加载过程的早期使用字符串替换功能,并且尚未加载s.el或不需要全部功能,那就可以了。s-replace好吧,这是from的定义s.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))
Run Code Online (Sandbox Code Playgroud)


phi*_*ils 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.
Run Code Online (Sandbox Code Playgroud)
(string-replace FROMSTRING TOSTRING INSTRING)

Replace FROMSTRING with TOSTRING in INSTRING each time it occurs.

(string-replace ".*" "BAR" "foo.*bar.*baz")
 ? "fooBARbarBARbaz"
Run Code Online (Sandbox Code Playgroud)