我阻止对lisp函数进行编程,该函数标记字符串包含在另一个
中的次数我试过这个函数给我一个错误:
*** - +:“abc”不是数字
(defun string-contain (string1 string2)
(cond
((not (length string1)) nil) ; string1 est vide (pas besoin de le tester à chaque fois)
((> (length string1) (length string2)) nil) ; string1 est plus longue que chaine2
((string= string1 (subseq string2 0 (length string1))) string1)
(t (+ 1(string-include string1 (subseq string2 1))))))
谢谢
答案 0 :(得分:4)
一般情况下,当你进行字符串处理时,你应该尽量避免调用 subseq ,因为它会创建一个新的字符串,而你不想做所有的事情那个字符串分配。 Common Lisp中的许多序列处理函数都包含开始和结束参数,因此您可以指定要查找的序列的哪些部分。函数搜索在另一个序列中查找序列的出现,并返回第一个出现的索引。您可以使用新的:start2 值重复调用search,以便在字符串中越来越远地搜索。例如:
(defun search-all (needle haystack &key key (test 'eql)
(start1 0)
(end1 (length needle))
(start2 0)
(end2 nil)
(overlaps nil))
"Counts the number of times that NEEDLE appears in HAYSTACK. START1
and END1, and START2 and END2, are bounding index designators of
NEEDLE and HAYSTACK, respectively. If OVERLAPS is true, then
overlapping occurrences will be counted separately."
(do* ((len1 (- end1 start1)) ; length of needle (constant)
(upd (if overlaps 1 len1)) ; how much to increment pos
(occurrences 0 (1+ occurrences)) ; occurrences, increments by 1
(start2 start2 (+ pos upd)) ; start2, updated to pos+upd
(pos #1=(search needle haystack ; pos. of needle, or NIL
:start1 start1 :end1 end1
:start2 start2 :end2 end2
:test test :key key)
#1#))
((null pos) occurrences))) ; when pos is NIL, return occurrences
那里的一点可能有点令人困惑。 执行和执行* 循环中的变量绑定的格式为(变量[init-form [update-form]]),我们想要 pos 的 init-form 和 update-form 是相同的,即对搜索的调用。在Common Lisp代码中,您可以使用 #n = form ,然后使用 #n#稍后再次引用相同的表单。这就是为什么我使用#1 =(搜索...)作为 init-form ,然后#1#作为 update-form 。
以下是一些例子:
;; Find 'ab' within a 'abcdabcd'
(SEARCH-ALL "ab" "abcdabcd")
;;=> 2
;; Find 'cat' within a 'one cat two cat three cat'
(SEARCH-ALL "concatenate" "one cat two cat three cat" :START1 3 :END1 6)
;;=> 3
;; Find 'cat' within 'one cat two cat'
(SEARCH-ALL "concatenate" "one cat two cat three cat" :START1 3 :END1 6 :START2
0 :END2 15)
;;=> 2
;; Fail to find 'cat' in 'Cat'
(SEARCH-ALL "cat" "Cat")
;;=> 0
;; Find 'cat' in 'Cat'
(SEARCH-ALL "cat" "Cat" :TEST 'CHAR-EQUAL)
;;=> 1
;; Find 2 'aaa' in 'baaaaaab' (no overlaps)
(SEARCH-ALL "aaa" "baaaaaab" :OVERLAPS NIL)
;;=> 2
;; Find 4 'aaa' in 'baaaaaab' (with overlaps)
(SEARCH-ALL "aaa" "baaaaaab" :OVERLAPS T)
;;=> 4
答案 1 :(得分:1)
查看代码,这看起来像是错误的来源:
((string= string1 (subseq string2 0 (length string1))) string1)
这一行将返回一个字符串,如果比较成功,它应该返回" 1加上检查string1是否在string2的头部,前面是一个字符"的值。 / p>
您可能还想跳过默认情况下的(+ 1 ...)
(不匹配)。并且你肯定希望在基本情况下返回0而不是nil
。
答案 2 :(得分:0)
(not (length string))
将始终为false或表示类型错误。您可能希望与zerop
进行比较。
答案 3 :(得分:0)
您的功能有肉眼发现的三个问题:
(not (length string1))
永远是nil
。nil
,在最后一个分支中返回一个数字。这种不一致可能会在将来引发问题。string-include
。以下是我如何解决这个问题。我们想要计算给定字符串包含在另一个字符串中的次数。这可以分为以下几种情况:
以下是实现它的代码:
(defun substring-times (substr string)
(cond ((> (length substr) (length string)) 0)
((and (= (length substr) (length string))
(string= substr string))
1)
((string= substr (subseq string 0 (length substr)))
(1+ (substring-times substr (subseq string (length substr)))))
(t 0)))
我们可以在
上测试它> (substring-times "ab" "abababababc")
5
此功能不包括“cab”中包含“ab”的情况。但这种变化是微不足道的(正如他们喜欢在书中说的那样,留下来作为练习)。
更有趣的是,这种函数效率低下(它在迭代时会使用递归)而不是Common Lisp中的惯用语。使用迭代重写它会很好:
(defun substring-times (substr string)
(let ((sublen (length substr))
(len (length string))
(result 0)
(i 0))
(loop
while (<= i (- len sublen))
if (string= substr string :start2 i :end2 (+ i sublen))
do (progn
(incf result)
(incf i sublen))
else
do (incf i)
end
finally (return result))))
此功能也可以处理“cabxabyab”的情况:
> (substring-times "ab" "cabxabyab")
3
编辑:我已将subseq
替换为string=
的关键字,如Rainer Joswig建议的那样。