How to compare double quotes in Clojure? - string

(= "\"" "\"") ;; true
(let [ss "123\""]
(doseq [s ss]
(println s (= "\"" s) (.equals "\"" s))))
;; 1 false false
;; 2 false false
;; 3 false false
;; " false false
Why false in second case ?

Note the type of the elements given to you by doseq:
(let [ss "123\""]
(doseq [s ss]
(println (type s))))
You'll see that they're characters, yet you're comparing them against a string. That will always be false since the types don't match.
Compare against a character instead:
(let [ss "123\""]
(doseq [s ss]
(println s (= \" s))))
1 false
2 false
3 false
" true

Related

DrRacket – Finding total number of vowels in list of characters

I am using DrRacket on the Beginner Language mode.
Code below:
(define vowels '(#\a #\e #\i #\o #\u))
(define total 0)
(define (any-in-list lst check)
(cond
[(empty? lst) (+ 0 total)]
[(member? (first lst) check) (add1 total)]
[else (any-in-list (rest lst) check)]))
(define (count-vowels string)
(any-in-list (string->list string) vowels))
(count-vowels "how do i do this?")
The total value stays stuck at 1. After debugging, I realized that the 2nd cond statement evaluates to #true and then stops. How can I keep it going for the rest of the list after updating the total value?
You forgot to recurse when you found a match.
Also, since total is 0, (+ 0 total) is always 0, and (add1 total) is always 1.
Don't try to use global variables and mutation - recurse and use the recursive value.
(cond
; The empty list contains nothing, so the result is 0.
[(empty? lst) 0]
; If the first element is a member, the result is
; one more than the count in the tail.
[(member? (first lst) check) (add1 (any-in-list (rest lst) check))]
; Otherwise, the count is the same as in the tail.
[else (any-in-list (rest lst) check)]))
molbdnilo's answer explains the OP's issue and provides a correct solution;
since "Beginner Language" is mentioned, it may be worth
looking at how a solution might be constructed using the method
for which BSL (Beginning Student language) in DrRacket is apparently intended.
Following the HtDF (How to Design Functions) recipe, one can write the following
stub, incorporating signature and purpose, and "check-expect" examples:
(Note: layout differs slightly from HtDF conventions)
(define (count-vowels str) ;; String -> Natural ) *stub define* ;; *signature*
;; produce the count of vowel characters in str ) *purpose statement*
0 ) ) *stub body* (a valid result)
(check-expect (count-vowels "") 0 ) ) *examples*
(check-expect (count-vowels "a") 1 ) )
(check-expect (count-vowels "b") 0 ) )
(check-expect (count-vowels "ab") 1 ) )
(check-expect (count-vowels "ae") 2 ) )
The first check-expect already passes; now write inventory and template;
count-vowels will have to do something with each character in the string, but there is no
standard BSL function or template for this. However there is a template for doing something
with the elements of a list:
(define (fn lox) ;; (Listof X) -> Y ) *template*
(cond )
[(empty? lox) ... ] #|base case|# ;; Y )
[else (... #|something|# ;; X Y -> Y )
(first lox) (fn (rest lox))) ])) )
(define vowels (list #\a #\e #\i #\o #\u)) ) *inventory*
(member? x lox) ;; X (Listof X) -> Bool )
(string->list str) ;; String -> (Listof Char) )
So count-vowels can be a composition of string->list with a function derived from this
template, for which stub, signature, and check-expects are:
(define (count-vowels-in-list loc) ;; (Listof Char) -> Natural
0)
(check-expect (count-vowels-in-list empty) 0 )
(check-expect (count-vowels-in-list (cons #\a '())) 1 ) ;; (+ 1 0)
(check-expect (count-vowels-in-list (cons #\b '())) 0 ) ;; (+ 0 0)
(check-expect (count-vowels-in-list (list #\a #\b)) 1 )
(check-expect (count-vowels-in-list (list #\a #\e)) 2 )
Expanding the template and looking at the first check-expect, the |base case| can be filled in:
(define (count-vowels-in-list loc) ;; (Listof Char) -> Natural
(cond
[(empty? loc) 0 ]
[else (|something| (first loc) (count-vowels-in-list (rest loc))) ]))
For the next two check-expects, (rest loc) will be '(), so (|something| #\a 0) => 1 but
(|something| #\b 0) => 0
What distinguishes #\a from #\b is that (member? #\a vowels) => #true but
(member? #\b vowels) => #false so a descriptive name for |something| is add-1-if-vowel:
(define (add-1-if-vowel chr n) ;; Char Natural -> Natural
(if (member? chr vowels)
(add1 n)
n))
So a complete solution developed by following this systematic design method is:
(define vowels (list #\a #\e #\i #\o #\u))
(define (add-1-if-vowel chr n) ;; Char Natural -> Natural
(if (member? chr vowels)
(add1 n)
n))
(define (count-vowels-in-list loc) ;; (Listof Char) -> Natural
(cond
[(empty? loc) 0 ]
[else (add-1-if-vowel (first loc) (count-vowels-in-list (rest loc))) ]))
(define (count-vowels str) ;; String -> Natural
(count-vowels-in-list (string->list str)))
(check-expect (count-vowels "") 0 )
(check-expect (count-vowels "a") 1 )
(check-expect (count-vowels "b") 0 )
(check-expect (count-vowels "ab") 1 )
(check-expect (count-vowels "ae") 2 )
(check-expect (count-vowels "how do i do this?") 5 ) ;; ^ (this is how :) ^

Split String by Delimiter and Include Delimiter - Common Lisp

How can I split a string by a delimiter in Common Lisp, like is done in SPLIT-SEQUENCE, but also add the delimiter in the list of strings?
For example, I could write:
(split-string-with-delimiter #\. "a.bc.def.com")
and the result would be ("a" "." "bc" "." "def" "." "com").
I've tried the following code (make-adjustable-string makes a string that can be extended with vector-push-extend):
(defun make-adjustable-string (s)
(make-array (length s)
:fill-pointer (length s)
:adjustable t
:initial-contents s
:element-type (array-element-type s)))
(defun split-str (string &key (delimiter #\ ) (keep-delimiters nil))
"Splits a string into a list of strings, with the delimiter still
in the resulting list."
(let ((words nil)
(current-word (make-adjustable-string "")))
(do* ((i 0 (+ i 1))
(x (char string i) (char string i)))
((= (+ i 1) (length string)) nil)
(if (eql delimiter x)
(unless (string= "" current-word)
(push current-word words)
(push (string delimiter) words)
(setf current-word (make-adjustable-string "")))
(vector-push-extend x current-word)))
(nreverse words)))
But this doesn't print out the last substring/word. I'm not sure what's going on.
Thanks for the help ahead of time!
If you're just looking for a solution, and not for an exercise, you can use cl-ppcre:
CL-USER> (cl-ppcre:split "(\\.)" "a.bc.def.com" :with-registers-p t)
("a" "." "bc" "." "def" "." "com")
Something like this?
copy sub-strings using subseq
using LOOP makes collecting things easier
Example:
(defun split-string-with-delimiter (string
&key (delimiter #\ )
(keep-delimiters nil)
&aux (l (length string)))
(loop for start = 0 then (1+ pos)
for pos = (position delimiter string :start start)
; no more delimiter found
when (and (null pos) (not (= start l)))
collect (subseq string start)
; while delimiter found
while pos
; some content found
when (> pos start) collect (subseq string start pos)
; optionally keep delimiter
when keep-delimiters collect (string delimiter)))
Example:
CL-USER 120 > (split-string-with-delimiter "..1.2.3.4.."
:delimiter #\. :keep-delimiters nil)
("1" "2" "3" "4")
CL-USER 121 > (split-string-with-delimiter "..1.2.3.4.."
:delimiter #\. :keep-delimiters t)
("." "." "1" "." "2" "." "3" "." "4" "." ".")
CL-USER 122 > (split-string-with-delimiter "1.2.3.4"
:delimiter #\. :keep-delimiters nil)
("1" "2" "3" "4")
CL-USER 123 > (split-string-with-delimiter "1.2.3.4"
:delimiter #\. :keep-delimiters t)
("1" "." "2" "." "3" "." "4")
Or modified to work with any sequence (lists, vectors, strings, ...):
(defun split-sequence-with-delimiter (sequence delimiter
&key (keep-delimiters nil)
&aux (end (length sequence)))
(loop for start = 0 then (1+ pos)
for pos = (position delimiter sequence :start start)
; no more delimiter found
when (and (null pos) (not (= start end)))
collect (subseq sequence start)
; while delimiter found
while pos
; some content found
when (> pos start) collect (subseq sequence start pos)
; optionally keep delimiter
when keep-delimiters collect (subseq sequence pos (1+ pos))))
The problem is after the end condition of the do* loop. When variable i reaches the end of the string, the do* loop is exited but there is still a current-word which has not been added yet to words. When the end condition is met you need to add x to current-word and then current-word to words, before exiting the loop:
(defun split-string-with-delimiter (string delimiter)
"Splits a string into a list of strings, with the delimiter still
in the resulting list."
(let ((words nil)
(current-word (make-adjustable-string "")))
(do* ((i 0 (+ i 1))
(x (char string i) (char string i)))
((>= (+ i 1) (length string)) (progn (vector-push-extend x current-word) (push current-word words)))
(if (eql delimiter x)
(unless (string= "" current-word)
(push current-word words)
(push (string delimiter) words)
(setf current-word (make-adjustable-string "")))
(vector-push-extend x current-word)))
(nreverse words)))
However, note that this version is still buggy in that if the last character of string is a delimiter, this will be included into the last word, i.e. (split-string-with-delimiter "a.bc.def." #\.) => ("a" "." "bc" "." "def.")
I'll let you add this check.
In any case, you might want to make this more efficient by looking ahead for delimiter and extracting all the characters between the current i and the next delimiter at once as one single substring.
For the case that you want to split with many delimiters, and keep them:
(defun split-string-with-delims (str delims)
(labels ((delim-p (c)
(position c delims))
(tokens (stri test)
(when (> (length stri) 0)
(let ((p (position-if test stri)))
(if p
(if (= p 0)
(cons (subseq stri 0 (1+ p))
(tokens (subseq stri (1+ p) nil) test))
(cons (subseq stri 0 p)
(tokens (subseq stri p nil) test)))
(cons stri nil))))))
(tokens str #'delim-p)))
And you can call it either:
(split-string-with-delims ".,hello world,," '(#\. #\, #\ ))
; => ("." "," "hello" " " "world" "," ",")
or:
(split-string-with-delims ".,hello world,,!!" "., ")
; => ("." "," "hello" " " "world" "," "," "!!")
Concerning your code, since there is subseq, i'd go for Rainer Joswig's way(above), instead of your make-adjustable-string + vector-push-extend.

loop over characters in string, NewLISP

I need to loop over the characters in a given string--in Ruby, I'd do something like this:
string = "blah"
string.each_char do |c|
puts c
end
How do I do this in newLisp?
Note that dostring supplies integers:
(let (str "😄😃😀😊")
(dostring (c str)
(println (format "%x" c))))
1f604
1f603
1f600
1f60a
whereas explode supplies the characters:
(let (str "😄😃😀😊")
(dolist (c (explode str))
(println c)))
😄
😃
😀
😊
I figured it out:
(let (str "blah")
(dostring (c str)
(println (char c) )))

clojure remove last entrance of pattern in string

I have a string and some pattern at the end of the string. How can I remove this pattern exactly at the end of the word but nothing more even if it exists in the beginning or in the middle. For example, the string is
PatternThenSomethingIsGoingOnHereAndLastPattern
and I need to remove the "Pattern" at the end so that result would be
PatternThenSomethingIsGoingOnHereAndLast
How can I do that?
Your question doesn't specify if the pattern has to be a regex or a plain string. In the latter case you could just use the straightforward approach:
(defn remove-from-end [s end]
(if (.endsWith s end)
(.substring s 0 (- (count s)
(count end)))
s))
(remove-from-end "foo" "bar") => "foo"
(remove-from-end "foobarfoobar" "bar") => "foobarfoo"
For a regex variation, see the answer of Dominic Kexel.
You can use replaceAll
=> (.replaceAll "PatternThenSomethingIsGoingOnHereAndLastPattern" "Pattern$" "")
"PatternThenSomethingIsGoingOnHereAndLast"
or clojure.string/replace
=> (clojure.string/replace "PatternThenSomethingIsGoingOnHereAndLastPattern" #"Pattern$" "")
"PatternThenSomethingIsGoingOnHereAndLast"
Everything you need here I do believe
(def string "alphabet")
(def n 2)
(def m 4)
(def len (count string))
;starting from n characters in and of m length;
(println
(subs string n (+ n m))) ;phab
;starting from n characters in, up to the end of the string;
(println
(subs string n)) ;phabet
;whole string minus last character;
(println
(subs string 0 (dec len))) ;alphabe
;starting from a known character within the string and of m length;
(let [pos (.indexOf string (int \l))]
(println
(subs string pos (+ pos m)))) ;lpha
;starting from a known substring within the string and of m length.
(let [pos (.indexOf string "ph")]
(println
(subs string pos (+ pos m)))) ;phab

write comparison string function

I fully understand the use of list in lisp but I 've got problem using string.
I try to write my own code of functions like string> or string< from common lisp to understand how lisp deals with string.
For example, abcde is bigger than abbb and returns 1.
I think that I will use the char function or do you think that I must use subseq ? or function that deals with ASCII code ?
Here are cases that I found :
-character 0 of each string are equal, we continue, with the next character.
-charactere 0 are different, one is smaller that other, we stop.
I need help about "go to the next character".
Thanks a lot !!
This is the Common Lisp version. You can just use ELT because
(type-of "a") => (SIMPLE-ARRAY CHARACTER (1))
(defun my-string< (a b &key (start 0))
(cond
((= start (length a) (length b))
nil)
((>= start (min (length a) (length b)))
(error "Undefined"))
((char= (elt a start) (elt b start))
(my-string< a b :start (1+ start)))
((char< (elt a start) (elt b start))
t)))
This is an implementation of a function that given two strings will return either -1, 0 or +1 depending on if the first is less than, equal or greater than the second.
In case one string is the initial part of the other then shorter string is considered to be "less than" the longer.
The algorithm is very simple... loops for every char until either the index gets past one of the strings or if a character is found to be different.
(defun strcmp (a b)
(do ((i 0 (1+ i))
(na (length a))
(nb (length b)))
((or (= i na) (= i nb) (char/= (elt a i) (elt b i)))
(cond
((= i na nb) 0) ;; Strings are identical
((= i na) -1) ;; a finished first
((= i nb) 1) ;; b finished first
((char< (elt a i) (elt b i)) -1) ;; Different char a < b
(t 1))))) ;; Only remaining case
(defun test (a b)
(format t "(strcmp ~s ~s) -> ~s~%"
a b (strcmp a b)))
(test "abc" "abc")
(test "ab" "abc")
(test "abc" "ab")
(test "abd" "abc")
(test "abc" "abd")
The output is
(strcmp "abc" "abc") -> 0
(strcmp "ab" "abc") -> -1
(strcmp "abc" "ab") -> 1
(strcmp "abd" "abc") -> 1
(strcmp "abc" "abd") -> -1
Your problem has been solved already but in case you run into others,
the following method might be useful:
I installed SBCL from source and keep the source around.
That allows me to run M-. on a function name like string<
and it will jump to the definition in your lisp implementation.
In my case I ended up at this macro:
;;; LESSP is true if the desired expansion is for STRING<* or STRING<=*.
;;; EQUALP is true if the desired expansion is for STRING<=* or STRING>=*.
(sb!xc:defmacro string<>=*-body (lessp equalp)
(let ((offset1 (gensym)))
`(with-two-strings string1 string2 start1 end1 ,offset1 start2 end2
(let ((index (%sp-string-compare string1 start1 end1
string2 start2 end2)))
(if index
(cond ((= (the fixnum index) (the fixnum end1))
,(if lessp
`(- (the fixnum index) ,offset1)
`nil))
((= (+ (the fixnum index) (- start2 start1))
(the fixnum end2))
,(if lessp
`nil
`(- (the fixnum index) ,offset1)))
((,(if lessp 'char< 'char>)
(schar string1 index)
(schar string2 (+ (the fixnum index) (- start2 start1))))
(- (the fixnum index) ,offset1))
(t nil))
,(if equalp `(- (the fixnum end1) ,offset1) nil))))))
) ; EVAL-WHEN
There is no direct concept of iteration ("next") with strings, in Scheme. That only applies to lists. So instead you have to iterate with indices:
(define (string<? lhs rhs)
(let* ((lhslen (string-length lhs))
(rhslen (string-length rhs))
(minlen (min lhslen rhslen)))
(let loop ((i 0))
(if (= i minlen) (< lhslen rhslen)
(let ((lhschar (string-ref lhs i))
(rhschar (string-ref rhs i)))
(cond ((char<? lhschar rhschar) #t)
((char<? rhschar lhschar) #f)
(else (loop (+ i 1)))))))))

Resources