Lisp:多级搜索和替换

时间:2013-07-16 20:45:17

标签: replace lisp

我想写一个lisp函数,它在字符串中进行多次搜索和替换。例如,我想将"a""t"分别替换为字符"e"中的"d""bat"

我该怎么做?

3 个答案:

答案 0 :(得分:3)

这是一个纯功能版本:

(map 'string (lambda (c)
               (case c
                 (#\a #\e)
                 (#\t #\d)
                 (t c)))
     "bat")
==> "bed"

为了使这个更通用,你可以在编译时使用宏构建lambda:

(defmacro make-translation-lambda (from to)
  `(lambda (c) (case c ,@(map 'list (lambda (i o) `(,i ,o)) from to) (t c))))
(map 'string (make-translation-lambda "at" "ed") "bat")
==> "bed"

请注意,宏make-translation-lambda的参数必须是字符串文字。

或者,更灵活但效率更低,你可以做到

(defun translate-string (input from to)
  (assert (= (length from) (length to)))
  (map 'string
       (lambda (c)
         (let ((pos (position c from)))
           (if pos
               (char to pos)
               c)))
       input))
(translate-string "bed" "at" "ed")
==> "bed"

使用宏make-translation-lambda的版本的性能与正在翻译的字符串呈线性关系(O(length(input)))。

函数translate-string的效果为O(length(input) * length(from))

答案 1 :(得分:1)

如果您希望一次从原始字符串替换一个字符,类似于tr unix实用程序的工作方式,您应该processing the string one character a time并收集转换后的字符:

(defun transform-chars (replacements str)
  "replacements is a list of lists: (FROM-CHAR TO-CHAR)"
  (coerce
    (loop for char across str
          for tr = (assoc char replacements)
          if (null tr) collect char
          else collect (second tr))
    'string))

(transform-chars '((#\a #\e) (#\t #\d)) "bat")

我在这些子句中使用LOOP宏:

我们也是coercing the collected characters from a list into a string

答案 2 :(得分:0)

仅供记录:

(defun make-sparse-charmap (from to)
  (loop with map =
       (loop with map = (make-string 128 :initial-element #\x)
          for i from 0 below 128 do
            (setf (char map i) (code-char i))
          finally (return map))
     for x across from
     for y across to do
       (setf (char map (char-code x)) y)
     finally (return map)))

(defun tr (source from to)
  (loop with map = (make-sparse-charmap from to)
     and result = (make-string (length source) :initial-element #\x)
     for c across source
     for i from 0 do
       (setf (char result i) (char map (char-code c)))
     finally (return result)))

对于Unicode字符串来说,这可能不是最好的主意,但对于ASCII来说,这样做很好。

修改

略微修改它,没有额外的lambdas生成。