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

Blu*_*ger 5 function sbcl common-lisp

我有一个查询request-uri,形式为"/ node/143"(只是格式的一个例子).

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

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

(setq request-uri "/node/143")
Run Code Online (Sandbox Code Playgroud)

当我检查变量时,我已将此返回.

request-uri
"/node/143"
Run Code Online (Sandbox Code Playgroud)

我现在尝试删除第一个斜杠(此时它只是用于查看函数如何正确使用的任何内容).

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

(remove '/ request-uri)
"/node/143"
Run Code Online (Sandbox Code Playgroud)

我甚至尝试过提供一份清单

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

(remove '('/) request-uri)
"/node/143"
Run Code Online (Sandbox Code Playgroud)

尽管字符串是字符的向量,但我认为不管怎样,整个字符串可能放在一个单元格中,我试图删除整个字符,但仍然没有运气.

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

(remove '/node143 request-uri)
"/node/143"
Run Code Online (Sandbox Code Playgroud)

所以我现在感到很茫然,这个看似简单的功能确实让我无法理解,我以为我按照文档的说法去了,但没有任何工作.

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

谢谢.

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

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

(remove #\/ request-uri)
Run Code Online (Sandbox Code Playgroud)

整个字符串怎么样?

`(remove #\node request-uri`)
Run Code Online (Sandbox Code Playgroud)

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

(remove "node" request-uri)
(remove 'node request-uri)
(remove ?\node request-uri)
(remove #\node request-uri)
(remove '("node") request-uri)
Run Code Online (Sandbox Code Playgroud)

我不确定这里应该怎么解决.

Rai*_*wig 7

学习阅读Common Lisp HyperSpec

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

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

remove item sequence &key from-end test test-not start end count key
    => result-sequence
Run Code Online (Sandbox Code Playgroud)

字符串是字符序列。因此,删除的调用将是:

(remove #\/ "/foo/")
Run Code Online (Sandbox Code Playgroud)

或(例如)

(remove #\/ "/foo/" :start 2)
Run Code Online (Sandbox Code Playgroud)

记住:#\a是一个字符。 #\node是没有性格。非法的。一个字符串是"/foo/"

从字符串中 REMOVE 的项目必须是一个字符。没有其他的。为什么?因为默认情况下 TEST 是 EQL 并且 EQL 将字符串中的字符与您的项目参数进行比较。此外,默认情况下键是 IDENTITY,不会更改项目。

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

 (remove "/" "/abc/" :key #'string :test #'equal)
Run Code Online (Sandbox Code Playgroud)

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

另一种方法是:

 (remove "/" "/abc/" :test (lambda (a b) (eql (aref a 0) b)))
Run Code Online (Sandbox Code Playgroud)

以上检索"/"每个测试中的第一个字符,并将其与字符串中的字符进行比较"/abc/"。同样的代价是它需要获得角色五次(在这个例子中)。

所以如果你的原始对象是一个字符串,最好的写法是:

(remove (aref "/" 0) "/abc/")
Run Code Online (Sandbox Code Playgroud)

上面我们从字符串中获取"/"一次字符,然后 REMOVE 将此字符与默认 EQL 测试与字符串中的每个字符进行比较 - 它返回一个新字符串,其中包含不是 EQL 的那些字符#\/

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

(remove "foo" "afoob")不起作用,因为字符串("foo"此处)不是字符串的元素。请记住,字符是字符串的元素。还请记住,带有一项的字符串"/"仍然是字符串而不是字符。因此"/"#\/是不同的类型。第一个是字符串,第二个是字符。

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

(subseq "0123456" 1 5)
     where 1 is the start and 5 is the end index.
Run Code Online (Sandbox Code Playgroud)

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

(concatenate 'string "abc" "123")
  returns a new string with the strings "abc" and "123" appended.
Run Code Online (Sandbox Code Playgroud)

要删除字符串的一部分,另请参见函数 STRING-TRIM、STRING-LEFT-TRIM 和 STRING-RIGHT-TRIM。

因此,与从字符串中删除子字符串的另一个答案一样,您需要编写一些代码来提取一些字符串,然后将它们连接起来。

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

  • 不要使用 CLtL2 作为第一个来源。它已经过时了。HyperSpec 基于 ANSI 标准。CLtL2 不是。CLtL2 描述了工作完成之前标准化过程中的一些语言版本。 (2认同)