How do I format a single backslash in common lisp?
Asked Answered
G

2

6

I'm currently trying to get an output of ... \hline in GNU Common lisp 2.49, but I can't get the format to work. This is what I've tried so far to get a single backslash:

(format nil "\ ") => " "
(format nil "\\ ") => "\\ "
(format nil "\\\ ") => "\\ "

I thought that the double backslash would make it work, why isn't the backslash escaping just the other backslash?

Gelderland answered 12/10, 2018 at 15:38 Comment(1)
Note that you don't do any output. You create data - here a string - which then is printed by the REPL. If you want do output with FORMAT, you need to give FORMAT a stream instead of NIL.Hannahannah
H
6

Note the difference between creating a string and actually doing output to a stream:

CL-USER 69 > (format nil "\\ ")
"\\ "                               ; result

CL-USER 70 > (format t "\\ ")
\                                   ; output
NIL                                 ; result

CL-USER 71 > (format *standard-output* "\\ ")
\                                   ; output
NIL                                 ; result
Hannahannah answered 12/10, 2018 at 18:55 Comment(0)
T
8

See for example:

CL-USER> (write "\\" :escape nil)
\
"\\"

Here above, the first backslash is your string, printed without escaping backslashes. The returned value is the string, printed by the REPL with the standard io syntax (http://clhs.lisp.se/Body/m_w_std_.htm), which escapes strings.

So, your string contains a single backslash, but is printed in such a way that it can be read back, hence the need to escape the backslash in the output string.

Note also that calling format with NIL and a single string returns the same string.

You can inspect your strings, for example by mapping each character to its name:

(loop
   for input in '("\ " 
                  "\\ "
                  "\\\ ")
   collect (list :input input
                 :characters (map 'list #'char-name input)))

This gives:

((:INPUT " " :CHARACTERS ("Space"))
 (:INPUT "\\ " :CHARACTERS ("REVERSE_SOLIDUS" "Space"))
 (:INPUT "\\ " :CHARACTERS ("REVERSE_SOLIDUS" "Space")))

Or, simply use inspect:

CL-USER> (inspect "\\hline")

The object is a VECTOR of length 6.
0. #\\
1. #\h
2. #\l
3. #\i
4. #\n
5. #\e
Troop answered 12/10, 2018 at 15:49 Comment(1)
This is a thorough and wonderful answer, which teaches you other inspecting-fus too. Thank you!Berey
H
6

Note the difference between creating a string and actually doing output to a stream:

CL-USER 69 > (format nil "\\ ")
"\\ "                               ; result

CL-USER 70 > (format t "\\ ")
\                                   ; output
NIL                                 ; result

CL-USER 71 > (format *standard-output* "\\ ")
\                                   ; output
NIL                                 ; result
Hannahannah answered 12/10, 2018 at 18:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.