Common Lisp:删除函数,它是如何使用的?

时间:2009-03-21 14:50:17

标签: function common-lisp sbcl

我有一个以“/ node / 143”形式的查询request-uri(只是格式的一个例子)。

我想从字符串中删除第一个正斜杠,我查找了函数remove并尝试了一下。我似乎无法让它工作(我在Linux上使用SBCL)。

我已使用此代码设置了request-uri。

(setq request-uri "/node/143")

当我检查变量时,我已将其返回。

request-uri
"/node/143"

我现在尝试删除第一个斜杠(此时它只是用于查看函数的正确使用方式)。

(remove "/" request-uri)
"/node/143"

(remove '/ request-uri)
"/node/143"

我甚至试过提供一个列表

(remove '("/") request-uri)
"/node/143"

(remove '('/) request-uri)
"/node/143"

即使字符串是vectors of characters,我还是觉得整个字符串可能放在一个单元格中,我试图删除整个字符串,但仍然没有运气。

(remove "/node/143" request-uri)
"/node/143"

(remove '/node143 request-uri)
"/node/143"

所以我现在感到很茫然,这个看似简单的功能确实让我无法理解,我以为我跟着文件写了这封信,但没有任何效果。

任何人都可以了解这里发生的事情吗?

感谢。

编辑:我找到了问题的答案,提出了另一个问题。

从我使用的字符串中删除元素

(remove #\/ request-uri)

整个字符串怎么样

`(remove #\node request-uri`)

仅适用于第一个字符并引发错误,以下所有内容均无效。

(remove "node" request-uri)
(remove 'node request-uri)
(remove ?\node request-uri)
(remove #\node request-uri)
(remove '("node") request-uri)

我不确定应该如何处理这个问题。

4 个答案:

答案 0 :(得分:4)

学习阅读Common Lisp HyperSpec

字符串是SequencesArrays(字符的一维向量),以及Strings。这意味着大多数这些功能都适用。

让我们看一下REMOVE。 CLHS给出了这个签名:

remove item sequence &key from-end test test-not start end count key
    => result-sequence

字符串是字符序列。所以删除的电话将是:

(remove #\/ "/foo/")

或(例如)

(remove #\/ "/foo/" :start 2)

请记住:#\ a是一个角色。 #\ node不是字符。非法。字符串是“/ foo /".

要从字符串中删除的项目必须是一个字符。没有其他的。为什么?因为默认情况下TEST是EQL和EQL将字符串中的字符与item参数进行比较。此外,密钥默认为IDENTITY,不会更改项目。

如果您的参数是字符串怎么办?那么,你必须做更多的事情:

 (remove "/" "/abc/" :key #'string :test #'equal)

这会查看序列的每个字符并将其转换为字符串。然后使用EQUAL函数将字符串与项目“/”进行比较。这也有效。成本是需要从“/ abc /”的每个字符生成一个字符串,每个字符串都是一个新对象。

另一种方法是:

 (remove "/" "/abc/" :test (lambda (a b) (eql (aref a 0) b)))

上面检索每个测试中的第一个字符“/”,并将其与字符串“/ abc /”中的字符进行比较。再次成本是它需要五次获得角色(在这个例子中)。

因此,如果您的原始对象是字符串,那么写它的最好方法是:

(remove (aref "/" 0) "/abc/")

上面我们从字符串“/”获取一次字符,然后REMOVE将此字符与字符串中每个字符的默认EQL测试进行比较 - 它返回一个新字符串,这些字符不是EQL到#/。 / p>

你期待什么?\ foo是什么?在Common Lisp中,这是符号|?fOO |。

另外(删除“foo”“afoob”)不起作用,因为字符串(此处为“foo”)不是字符串的元素。请记住,字符是字符串的元素。还要记住,带有“/”之类的项目的字符串仍然是字符串而不是字符。因此“/”和#/是不同类型的。第一个是字符串,第二个是字符。

SUBSEQ从序列中提取序列。这意味着它还从另一个字符串中提取字符串:

(subseq "0123456" 1 5)
     where 1 is the start and 5 is the end index.

CONCATENATE附加序列。这意味着它还会附加字符串。

(concatenate 'string "abc" "123")
  returns a new string with the strings "abc" and "123" appended.

要删除部分字符串,请参阅STRING-TRIM,STRING-LEFT-TRIM和STRING-RIGHT-TRIM函数。

所以,正如另一个从字符串中删除子串的答案一样,你需要编写一些代码来提取一些字符串,然后将它们连接起来。

SEARCH搜索字符串中的字符串。

答案 1 :(得分:2)

要删除整个子字符串,您必须创建一个新函数,例如:

(defun remove-string (rem-string full-string &key from-end (test #'eql)
                      test-not (start1 0) end1 (start2 0) end2 key)
  "returns full-string with rem-string removed"
  (let ((subst-point (search rem-string full-string 
                             :from-end from-end
                             :test test :test-not test-not
                             :start1 start1 :end1 end1
                             :start2 start2 :end2 end2 :key key)))
    (if subst-point
        (concatenate 'string
                     (subseq full-string 0 subst-point)
                     (subseq full-string (+ subst-point (length rem-string))))
        full-string)))

这只是一个起点。我复制了SEARCH的所有选项,但我认为某些选项在这种情况下没有意义。至少这是有效的:

(remove-string "node" "this is a node or not")

对于更复杂的案例,你或许应该看看cl-ppcre,一个正则表达式库。

答案 2 :(得分:2)

说明:

(remove "node" request-uri)
(remove 'node request-uri)
(remove ?\node request-uri)
(remove #\node request-uri)
(remove '("node") request-uri)

这些是(分别):字符串,(引用)符号,(已评估)符号,格式错误的字符文字和包含一个字符串的列表。 REMOVE从对象序列中删除一个对象,而一个字符串不是任何这些东西的序列。

如果您只想删除部分字符串,SUBSEQ可能会解决这个问题:

(let ((uri "/node/143"))
  (when (string= (subseq uri 0 6) "/node/")
    (format t "user wants node ~D" (parse-integer (subseq uri 6)))))

对于更复杂的事情,您可能需要一个像cl-ppcre和/或split-sequence这样的库。 (如果你正在使用Hunchentoot,你已经加载了前者。)

答案 3 :(得分:0)

此操作失败,因为“/”是字符串,而不是字符。

(remove "/" request-uri)
"/node/143"

如果你想要角色,你需要使用#/即正斜杠字符。

(remove #\/ request-uri)
"node143"

但正如您所看到的,它将删除所有正斜杠。根据您链接的doc页面,remove会使用一个名为:count的关键字参数,该参数表示要删除的项目数。所以你可以这样做。

(remove #\/ request-uri :count 1)
"node/143"

希望这有帮助。

:: EDIT ::

不是吗?/,是#/。谢谢道格拉斯!