How to initialize a string with a fill pointer in Common Lisp? - string

I want to use formatted output in a loop to generate a string. Manual says it can be easily done by giving format function a string with a fill pointer as a destination. Unfortunately, it is not transparent from the manual how to initialize this string in the first place.
I tried (string "") and (format nil "") with no luck.
(make-array 0 :element-type 'character :fill-pointer 0) did work for me, but it just doesn't feel right.
What is the proper way to initialize a string with a fill pointer?

(make-array estimated-size-of-final-string
:element-type 'character :fill-pointer 0)
(with :adjustable t too if the estimate is inaccurate) is one way; for accumulating output to produce a string it may be more idiomatic to use with-output-to-string:
(with-output-to-string (stream)
(loop repeat 8 do (format stream "~v,,,'-#A~%" (random 80) #\x)))
=>
"----------------------------------x
--------x
--------------------------------------x
----------------------------------------------------------------x
--------------x
-----------------------------------------x
---------------------------------------------------x
-----------------------------------------------------------x
"

(make-array 0 :element-type 'character :fill-pointer 0) is the canonical way (well, it's quite possible to use an initial non-zero length and use :initial-contents with a string value). It's also possible to specify the fil-pointer value as t, that will set the fill-pointer at the end of the string.

Using FORMAT to a string with a fill pointer is a very rarely used functionality.
CL-USER 125 > (let ((s (make-array 0
:element-type 'character
:adjustable t
:fill-pointer t)))
(format s "Hello, ~a!" 'bill)
s)
"Hello, BILL!"
CL-USER 126 > (describe *)
"Hello, BILL!" is an (ARRAY CHARACTER (12))
FILL-POINTER 12
0 #\H
1 #\e
2 #\l
3 #\l
4 #\o
5 #\,
6 #\Space
7 #\B
8 #\I
9 #\L
10 #\L
11 #\!

Related

Accept string input from keyboard in LISP

am really new to LISP. I am using LispWorks and having issues on how to accept string input from the keyboard. Here is my code below compiles well but when I run, it gives an error:
"End of file while reading stream #<Synonym stream to
BACKGROUND-INPUT>."
(defun get-input (prompt)
(clear-input)
(write-string prompt)
(finish-output)
(let ((x (read-line)))
(write-string x)
(close x)))
(write-string (get-input "Enter a sentence: "))
(finish-output)
I have tried all sorts of codes using "read" to no avail, someone pls help.
The code below solved my problems:
(defun split-by-one-space (string)
(loop for i = 0 then (1+ j)
as j = (position #\Space string :start i)
collect (subseq string i j)
while j))
(defun rev_string()
(let ((mystr (read-line *query-io* NIL "")))
(terpri)
(format t "The Original String is : ~a~%" mystr)
(terpri)
(format t "The Reversed String By Character is : ~a~%" (reverse mystr))
(terpri)
(format t "The Reversed String By Word is : ~a~%" (nreverse (split-by-one-space mystr)))))
(rev_string)

How can I convert this list of numbers and symbols into a string?

is there a way too convert a list like this into a normal string?
list->string does not work because it isn't a list of chars.
It is a bit problematic because the list consists of symbols and numbers :/
(list + 4 * 5 - 3 6) //-> "+4*5-36"
Standard Scheme
For numbers:
(number->string 123 10) ; ==> "123"
For symbols:
(symbol->string 'test) ; ==> "test"
So you can check what type it is and use the correct procedure to convert to string. You can use string-append so join more strings together.
(string-append (symbol->string '+)
(number->string 4)
(symbol->string '*)
(number->string 5)
(symbol->string '-)
(number->string 3)
(number->string 6))
; ==> "+4*5-36"
If you make a procedure any->string you can make a one level list to string like this with SRFI-1:
(foldr (lambda (e a) (string-append (any->string e) a))
""
'(+ 4 * 5 - 3 6))
; ==> "+4*5-36"
Racket
Racket has format. If you do (format "~a" data) it will produce a string:
(format "~a" '(+ 4 * 5 - 3 6))
; ==> "(+ 4 * 5 - 3 6)"
Note that the first element of (list + 4 * 5 - 3 6) isn't the symbol + since the variable + gets evaluated to a procedure that adds stuff. eg. (+ 3 4) ; ==> 7 and + ; ==> #<procedure:+> (in racket; implementation specific)
I will show you in mit-scheme:
(define input '(+ 4 * 5 - 3 6))
(fold-right (lambda (x acc)
(string-append ((cond ((number? x) number->string )
((symbol? x) symbol->string ))
(else (error "unknown case" x))
x)
acc))
""
input)
Example:
1 ]=>
(define input '(+ 4 * 5 - 3 6))
;Value: input
...
;Value: "+4*5-36"
In case the list contains more kind of symbolic expressions, apart from numbers and symbols, you extend the cond-statement with other cases.
Also, do not forget to quote the input, otherwise + gets evaluated to a strange value.

`.split` method in clojure returns unexpected results

For part of a class project I need to read in a file representing a graph in Clojure. Here is a link to an example file. The file structure for all the files I could possibly read in are such
c Unknown number of lines
c That start with "c" and are just comments
c The rest of the lines are edges
e 2 1
e 3 1
e 4 1
e 4 2
e 4 3
e 5 1
e 5 2
The issue that I am having is trying to split a line based on spaces. In my REPL I have done
finalproject.core> (.split "e 1 2" " ")
#<String[] [Ljava.lang.String;#180f214>
Which, I am not sure what it means exactly.. I think it refers to a memory locations of a String[] I am not sure why it is displayed like that though. If the insert a # in front of the split string, which I think denotes it is a regular expression I receive an error
finalproject.core> (.split "e 1 2" #" ")
ClassCastException java.util.regex.Pattern cannot be cast to java.lang.String
Currently my entire implementation of this module is, which I am pretty sure will work if I could properly use the split function.
(defn lineToEdge [line]
(cond (.startsWith line "e")
(let [split-line (.split line " ")
first-str (split-line 1)
second-str (split-line 2)]
((read-string first-str) (read-string second-str)))))
(defn readGraphFile [filename, numnodes]
(use 'clojure.java.io)
(let [edge-list
(with-open [rdr (reader filename)]
(doseq [line (line-seq rdr)]
(lineToEdge line)))]
(reduce add-edge (empty-graph numnodes) edge-list)))
I have not had a chance to test readGraphFile in any way but when I try to use lineToEdge with some dummy input I receive the error
finalproject.core> (lineToEdge "e 1 2")
ClassCastException [Ljava.lang.String; cannot be cast to clojure.lang.IFn
Suggestions as to where I went wrong?
In the following, your return value is an Array of type String.
finalproject.core> (.split "e 1 2" " ")
#<String[] [Ljava.lang.String;#180f214>
To use it more conveniently in Clojure, you can put it into a vector:
user=> (vec (.split "e 1 2" " "))
["e" "1" "2"]
You can also use the built in clojure.string namespace:
user=> (require '[clojure.string :as string])
nil
user=> (string/split "e 1 2" #" ")
["e" "1" "2"]
The source of your stack trace is here:
(let [split-line (.split line " ")
first-str (split-line 1)
second-str (split-line 2)] ...)
This gets a String Array, via .split, then attempts to call it as if it were a function. Perhaps you meant to use get here to access an element of the List by index? (get split-line 1) will get the element from split-line at index 1, etc.
You'll see another problem here:
((read-string first-str) (read-string second-str))
If I am reading your code properly, this will end up calling a number as if it were a function, with another number as an argument. Perhaps you intend to return a pair of numbers?
[(read-string first-str) (read-string second-str)]

how to retrieve errno from an os error?

This question is divided into two parts.
Part one:
I run this ...
1 (handler-case (posix:kill 1 0)
2 (error (the-condition) (prin1 (type-of the-condition)) (terpri)
3 (princ the-condition) (terpri)))
... and get this output:
SYSTEM::SIMPLE-OS-ERROR
UNIX error 1 (EPERM): Operation not permitted
I can use #'princ-to-string and parse the string to get the error number. But is there a more direct way to retrieve errno? Something like #'file-error-pathname, but for errno instead?
Part two:
Where in the documentation could I have found the answer to Part one?
Released version
The released version 2.49 does not have an accessor for the errno.
You can get it, however, thusly:
[4]> (setq c (nth-value 1 (ignore-errors (posix:kill 1 0))))
#<SYSTEM::SIMPLE-OS-ERROR #x00000002002634A1>
[5]> (describe c)
#<SYSTEM::SIMPLE-OS-ERROR #x000000020021AF69> is an instance of the CLOS class #1=#<STANDARD-CLASS SYSTEM::SIMPLE-OS-ERROR>.
Slots:
SYSTEM::$FORMAT-CONTROL =
"UNIX error ~S (EPERM): Operation not permitted
"
SYSTEM::$FORMAT-ARGUMENTS = (1)
"UNIX error ~S (EPERM): Operation not permitted
" is a simple 1 dimensional array (vector) of CHARACTERs, of size 47 (a ISO-8859-1 string).
(1) is a list of length 1.
[6]> (car (slot-value c 'SYSTEM::$FORMAT-ARGUMENTS))
1
Development version
The dev version in the tip of the mercurial repo has os-error instead:
[1]> (setq c (nth-value 1 (ignore-errors (posix:kill 1 0))))
#<OS-ERROR #x0000000200253301>
[2]> (describe c)
#<OS-ERROR #x0000000200253301> is an instance of the CLOS class #1=#<STANDARD-CLASS OS-ERROR>.
Slots:
SYSTEM::$CODE = 1
1 is an integer, uses 1 bit, is represented as a fixnum.
[6]> (apropos "os-error")
OS-ERROR class
OS-ERROR-CODE function
EXT::OS-ERROR-CODE-1
[10]> (os-error-code c)
1

LISP- Delete vowels from a string

I want to write a function that deletes all vowels from a string. I thought of defining a function that detects the vowels, something similar to symbolp, zerop and so on and if it is a vowel, delete it. How can I do this? I would appreciate any input on this. Thanks
(defun deletevowels (string)
(go through the list
(if vowel-p deletevowels )
)
)
Nevertheless, I have the problem that deletes a vowel if it's the last, how can I modify this to meet what I want to do, to delete all vowels in a string? In the code below there's this function I was mentioning, vowel-p one.
(defun strip-vowel (word)
"Strip off a trailing vowel from a string."
(let* ((str (string word))
(end (- (length str) 1)))
(if (vowel-p (char str end))
(subseq str 0 end)
str)))
(defun vowel-p (char) (find char "aeiou" :test #'char-equal))
Moreover, is it easier if I would use the function below to turn the string into a list and then loop in the list instead of the string to look for the vowel and remove it?
(defun string-to-list (string)
(loop for char across string collect char))
CL-USER 27 > (defun vowel-p (char)
(find char "aeiou" :test #'char-equal))
VOWEL-P
CL-USER 28 > (remove-if #'vowel-p "abcdef")
"bcdf"
See: Common Lisp Hyperspec, REMOVE-IF.
CL-USER 29 > (defun deletevowels (string)
(remove-if #'vowel-p string))
DELETEVOWELS
CL-USER 30 > (deletevowels "spectacular")
"spctclr"

Resources