2

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

我怎样才能做到这一点?

4

3 回答 3

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-stringO(length(input) * length(from))

于 2013-07-16T23:03:21.270 回答
1

如果您想从原始字符串中一次替换一个字符,类似于tr unix 实用程序的工作方式,您应该一次处理一个字符并收集转换后的字符:

(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宏与这些子句一起使用:

我们还将从列表中收集的字符强制转换为字符串

于 2013-07-16T22:44:58.757 回答
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 生成。

于 2013-07-17T14:32:06.337 回答