2013-06-26 2 views
12

Sto cercando un equivalente di replace-regexp-in-string che utilizza solo stringhe letterali, nessuna espressione regolare.Ricerca di una funzione di sostituzione in stringa nell'elite

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

Ma io voglio

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

ho provato vari replace-* funzioni, ma non si può capire.

Modifica

In cambio delle risposte elaborate ho deciso di loro riferimento (sì, lo so tutti i parametri di riferimento sono sbagliati, ma è comunque interessante).

L'uscita del 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) 

replace-regexp-in-stringa con un vittorie regexp citati. I buffer temporanei funzionano molto bene.

Edit 2

Ora con compilation! Ha dovuto fare 10 volte di più di iterazione:

(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 sta cercando bene

+1

Il tempo per 'haxe-replace-string' è probabilmente così grave perché non lo hai compilato in byte? La macro 'loop' rende davvero la compilazione un must, altrimenti è molto lenta. –

+0

aggiornato con altri numeri – spike

+1

(replace-regexp-in-string "\\." "Bar" "foo.buzz") => "foobarbuzz" – vitaly

risposta

14

Prova questa:

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

Il penultimo secondo deve essere spostato all'esterno, ma in caso contrario sì, questo funziona . Non c'è costruito per questo? Sembra una cosa così strana da lasciare fuori. – spike

+0

@spike Ho letto da qualche parte che il modo suggerito è quello di creare un buffer temporaneo, copiare la stringa lì e "replace-string" sul buffer. Sarebbe interessante se fosse così più veloce. –

+1

@spike - risolto. –

3

che non avevo speranza per questo per essere più veloce:

(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 è una funzione nativa, ma non si sa mai ... Ad ogni modo, l'ho scritto qualche tempo fa per qualche ragione, quindi, se si compila come paragonare le prestazioni - siete invitati a provare :)

Un'altra idea, utilizzando buffer temporaneo:

(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))) 
8

s.el biblioteca manipolazione di stringhe ha s-replace funzione:

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

Si consiglia di installare s.el dal gestore pacchetti Emacs, se si lavora con le stringhe nel proprio Elisp.