How to convert a list into a string in lisp - lisp

How do you convert a list into a string? I am trying to use parse-int to take a list of numbers and convert them to decimal, but i end up getting an error saying "The control-string must be a string, not (contents)".
I'm using format, but I'm not sure if I'm using it incorrectly.
Here's my code:
(princ "Enter a or list of hexadecimal numbers: ")
(setq numList (read-from-string (concatenate 'string "(" (read-line) ")")))
(defun hextodec(nums)
(setq numString (format "%s" nums))
(setq newNum (parse-integer numString :radix 16))
(write nums)
(princ " = ")
(write newNum)
) ;This will format the number that the user enters
(hextodec numList)

Since you're using read-from-string anyway, you can just tell Lisp's reader to read base 16 integers:
;; CLISP session
[1]> (let ((*read-base* 16)) (read-from-string "(9 A B C F 10)"))
(9 10 11 12 15 16) ;
14
read-from-string is a potential security hole if the contents of the string are untrusted input, because of the hash-dot evaluation notation.
When using the Lisp reader on untrusted data, be sure bind *read-eval* to nil.
[2]> (read-from-string "(#.(+ 2 2))")
(4) ;
11
Note how the #. notation causes the + function specified in the string data to be executed. That could be any function, such as something that whacks files in your filesystem, or sends sensitive data to a remote server.

Format's first argument is the stream to print to. You seem to intend to return the string instead of printing, so you should put nil there: (format nil "~s" nums)
The format control string "%s" does not contain any format directives. The entire format form does not make much sense here, as you seem to intend to loop over the given nums instead. You should employ some looping construct for that, e. g. loop, do, map, mapcar ….

Related

How do I count the number of specific characters in a string in Emacs Lisp?

Let's say I have a string s.
And this string s could contain this:
asdf-asdfasdfasf-fasdf-asdfasdfasdf
or this:
asf-asdfaf
but also this:
aasdaf
How do I count the number of dashes (-) in this string using Emacs Lisp and store this number in some variable e.g. count-of-dashes?
The following function should do it:
(defun count-chars (char str)
(let ((s (char-to-string char))
(count 0)
(start-pos -1))
(while (setq start-pos (string-search s str (+ 1 start-pos)))
(setq count (+ 1 count)))
count))
You call it like this:
(count-chars ?- "---") ==> 3
(count-chars ?- "foo-bar") ==> 1
(count-chars ?- "-foo-bar-baz") ==> 3
(count-chars ?- "foobarbaz") ==> 0
To set a variable to the number found, you just use
setq:
(setq count-of-chars (count-chars ?- "foo-bar-baz"))
Basically, we loop looking for the first dash: if we find it we remember where so that we start looking at the place just to the right of it the next time around the loop. The loop body then just counts every one we see. When we can't find any more, string-search (and the setq) returns nil and the loop exits, whereupon we return the accumulated count. See the doc string of the function string-search with C-h f string-search for the details.
Another method is more akin to the split string method of python: split-string splits a string on a separator into a list of parts. We then count the parts (the length of the list) and subtract 1: "a-b-c" is split into ("a" "b" "c") so there are three parts but only two separators.
(defun count-chars (char str)
(let ((s (char-to-string char)))
(- (length (split-string str s)) 1)))
Again, see the doc string of split-string (C-h f split-string) for all the details.
In both cases, we converted the character argument to a string argument, because both string-search in the first case and split-string in the second expect a string argument (to search for in the first case and to use as a separator in the second case - in fact, split-string can use a regular expression as a separator). Characters and strings are different data types in Emacs Lisp, so the conversion is necessary if you really want a character s the first argument of count-chars. But you could make it a string instead:
(defun count-seps (sep str)
(- (length (split-string str sep)) 1))
and then you would call it like this instead:
(count-seps "-" "abc-def-ghi-")
which is simpler and more general:
(count-seps "-;-" "abc-;-def") ==> 1
but you do have to worry about special characters in the separator string:
(count-seps "-*-" "abcd-------def") ==> 1
since the regular expression -*- matches one or more dashes so it matches all seven dashes: there is only one separator. Whether that's what you want is debatable. If you don't want it, you'd need to escape the special characters in the separator string:
(defun count-chars (sep str)
(let ((qsep (regexp-quote sep)))
(- (length (split-string str qsep)) 1)))

String addition assignment in lisp

I have a loop with a condition, based on which I decide whether I should append something to existing string or not.
In Python, it should look like (this is dummy code, just to show the idea):
result_str = ''
for item in range(5):
if item % 2 == 0:
result_str += str(item)
print(result_str)
Output: 024
So the question is: how can I perform addition assignment on strings (+=) in lisp?
String concatenation relies on the more general CONCATENATE function:
(concatenate 'string "a" "b")
=> "ab"
Since it considered verbose by some, you can find libraries that implement shorter versions:
(ql:quickload :rutils)
(import 'rutils:strcat)
And then:
(strcat "a" "b")
In order to assign and grow a string, you need to use SETF with an existing variable.
(let ((string ""))
(dotimes (i 5)
(when (evenp i)
(setf string (strcat string (princ-to-string i)))))
string)
A more idiomatic way in Lisp is to avoid string concatenation, but print in a stream which writes into a buffer.
(with-output-to-string (stream)
;; now, stream is bound to an output stream
;; that writes into a string. The whole form
;; returns that string.
(loop
for i from 0 below 5 by 2
do (princ i stream)))
=> "024"
Here above, stream is just the symbol used for naming the stream, you could use any other one, including *standard-output*, the special variable that represents current output stream. Doing so would make the enclosed code redirect its standard output to the string stream.
An alternative way to build the intermediate list is the following, where iota is a small utility in the alexandria library:
(delete-if #'oddp (alexandria:iota 5))
=> (0 2 4)
In order to produce a string, you can also use FORMAT, which has a directive that can iterate over lists:
(format nil "~{~a~}" '(0 2 4))
=> "024"
The nil stream destination represents a string destination, meaning (format nil ...) returns a string. Each directive starts with a tilde character (~), ~{ and ~} enclose an iteration directive; inside that block, ~a prints the value "aesthetically" (not readably).

Lisp string formatting with named parameters

Is there a way in Lisp to format a string using named parameters?
Perhaps something with association lists like
(format t "All for ~(who)a and ~(who)a for all!~%" ((who . "one")))
in order to print "All for one and one for all".
Similar to this python question, or this scala one, or even c++, but in Lisp.
If this functionality isn't in the language, does anyone have any cool functions or macros that could accomplish the same thing?
Use CL-INTERPOL.
(cl-interpol:enable-interpol-syntax)
String interpolation
For simple cases, you don't need FORMAT:
(lambda (who) #?"All for $(who) and $(who) for all!")
Then:
(funcall * "one")
=> "All for one and one for all!"
Interpret format directives
If you need to format, you can do:
(setf cl-interpol:*interpolate-format-directives* t)
For example, this expression:
(let ((who "one"))
(princ #?"All for ~A(who) and ~S(who) for all!~%"))
... prints:
All for one and "one" for all!
If you are curious, the above reads as:
(LET ((WHO "one"))
(PRINC
(WITH-OUTPUT-TO-STRING (#:G1177)
(WRITE-STRING "All for " #:G1177)
(FORMAT #:G1177 "~A" (PROGN WHO))
(WRITE-STRING " and " #:G1177)
(FORMAT #:G1177 "~S" (PROGN WHO))
(WRITE-STRING " for all!" #:G1177))))
Alternate reader function
Previously, I globally set *interpolate-format-directives*, which interprets format directive in all interpolated strings.
If you want to control precisely when format directives are interpolated, you can't just bind the variable temporarily in your code, because the magic happens at read-time. Instead, you have to use a custom reader function.
(set-dispatch-macro-character
#\#
#\F
(lambda (&rest args)
(let ((cl-interpol:*interpolate-format-directives* t))
(apply #'cl-interpol:interpol-reader args))))
If I reset the special variable to its default value NIL, then strings where directives are formatted are prefixed with #F, whereas normal interpolated ones use the #? syntax. If you want to change readtables, have a look at named readtables.

Common Lisp: read each input character as a list element

Lisp newbie here.
I want to read from standard-in a string of characters such as:
aabc
I want to convert that input into a list, where each character becomes a list element:
(a a b c)
And I want the list assigned to a global variable, text.
I created this function:
(defun get-line ()
(setf text (read)))
but that just results in assigning a single symbol to text, not tokenizing the input into a list of symbols.
What's the right way to implement get-line() please?
Here you go: First using coerce to convert the string to a list of characters, then mapcar to convert each character to a string.
(defun get-line ()
(setf text (mapcar 'string (coerce (string (read)) 'list))))
(loop
for x = (string-upcase (string (read-char)))
while (not (equal " " x))
collecting (intern x))
Note the upcase is there because symbols in CL are not case sensitive and are upcased by default by the reader.

Convert char to number

I'm in the process of reading a flat file - to use the characters read I want to convert them into numbers. I wrote a little function that converts a string to a vector:
(defun string-to-vec (strng)
(setf strng (remove #\Space strng))
(let ((vec (make-array (length strng))))
(dotimes (i (length strng) vec)
(setf (svref vec i) (char strng i)))))
However this returns a vector with character entries. Short of using char-code to convert unit number chars to numbers in a function, is there a simple way to read numbers as numbers from a file?
In addition to Rainer's answer, let me mention read-from-string (note that Rainer's code is more efficient than repeated application of read-from-string because it only creates a stream once) and parse-integer (alas, there is no parse-float).
Note that if you are reading a CSV file, you should probably use an off-the-shelf library instead of writing your own.
Above is shorter:
? (map 'vector #'identity (remove #\Space "123"))
#(#\1 #\2 #\3)
You can convert a string:
(defun string-to-vector-of-numbers (string)
(coerce
(with-input-from-string (s string)
(loop with end = '#:end
for n = (read s nil end)
until (eql n end)
unless (numberp n) do (error "Input ~a is not a number." n)
collect n))
'vector))
But it would be easier to read the numbers directly form the file. Use READ, which can read numbers.
Note that read-like functions are affected by reader macros.
Pick an example:
* (defvar *foo* 'bar)
*FOO*
* (read-from-string "#.(setq *foo* 'baz)")
BAZ
19
* *foo*
BAZ
As you can see read-from-string can implicitly set a variable. You can disable the #. reader macro by setting *read-eval* to nil but anyway if you have only integers on the input then consider using parse-integer instead.