I block to program lisp function that mark how many times a string is included in another
I tried this function that sends me an error:
*** - +: "abc" is not a number
(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))))))
Thank you
Looking at the code, this looks like the source of the error:
This line will return a string, if the comparison succeeds, it should probably return "1 plus the value of checking if string1 is at the 'head of string2, one character ahead".
You probably also want to skip the
(+ 1 ...)
in the default case (no match). And you definitely want to return 0 rather thannil
, in the base cases.In general, when you're doing string processing, you should try to avoid calling subseq, since it creates a new string, and you don't want to be doing all that string allocation. Many of the sequence processing functions in Common Lisp take start and end parameters, so that you can specify which parts of the sequence you're looking for. The function search looks for an occurrence of a sequence within another sequences and returns the index of the first occurrence. You can call search repeatedly with new :start2 values to search farther and farther within the string. For instance:
There's one bit in there that may be a bit confusing. The variable bindings in do and do* loops have the form (variable [init-form [update-form]]), and we want the init-form and update-form for pos to be the same, namely a call to search. In Common Lisp code, you can use #n=form and then use #n# to refer to the same form again later. That's why I've used the #1=(search …) as the init-form, and then #1# as the update-form.
Here are some examples:
(not (length string))
will always be either false or signal a type error. You probably want to compare to 0, withzerop
.Your function has three problems noticed with a naked eye:
(not (length string1))
will always benil
as Svante pointed out.nil
in two branches and a number in the last branch. This inconsistency may cause problems in the future.string-include
.Here is how I would approach this problem. We want to calculate number of times a given string is included in another string. This can be split into the following cases:
Here is the code that implements it:
We can test it on
This function does not cover the case of "ab" being contained in "cabxabyab". But the change is trivial (and as they like to say in books, left as an exercise).
More interesting is that this kind of function is inefficient (it uses recursion in place where iteration would do) and not idiomatic in Common Lisp. It would be nice to rewrite it using iteration:
This function will also be able to deal with the case of "cabxabyab":
EDIT: I have replaced
subseq
with keywords forstring=
as Rainer Joswig suggested.