繁体   English   中英

Common Lisp:Remove Function,它是如何使用的?

[英]Common Lisp: The Remove Function, how is it used?

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

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

我已经使用此代码设置了请求 uri。

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

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

request-uri
"/node/143"

我现在尝试删除第一个斜线(此时只需了解如何正确使用 function)。

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

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

我什至尝试提供一份清单

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

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

即使字符串是字符的向量,我认为可能整个字符串可能会放在一个单元格中,我试图删除整个内容,但仍然没有运气。

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

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

所以我现在不知所措,这个看似简单的 function 真的让我望而却步,我以为我是按照文档来的,但没有任何效果。

任何人都可以阐明这里发生的事情吗?

谢谢。

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

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

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

我不确定这里应该如何解决。

学习阅读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 参数进行比较。 默认情况下, key 是 IDENTITY 并且不会更改项目。

如果你的论点是一个字符串怎么办? 那么,你必须做更多:

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

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

另一种方法是:

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

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

因此,如果您的原始 object 以字符串形式出现,那么最好的编写方法是:

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

上面我们从字符串"/"中获取字符一次,然后 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.

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 在字符串中搜索字符串。

要删除整个 substring,您必须创建一个新的 function,例如:

(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,一个正则表达式库。

解释:

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

它们(分别)是:字符串、(引用的)符号、(评估的)符号、格式错误的字符文字和包含一个字符串的列表。 REMOVE从对象序列中删除 object,字符串不是这些事物的序列。

如果您只想删除部分字符串,则 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,则您已经加载了前者。)

这失败了,因为“/”是一个字符串,而不是一个字符。

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

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

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

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

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

希望这可以帮助。

::编辑::

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM