49

Basically, I'd like to do the following, only using Common Lisp instead of Python:

print("Hello world.\r\n") 

I can do this, but it only outputs the #\newline character and skips #\return:

(format t "Hello world.~%") 

I believe I could accomplish this using an outside argument, like this:

(format t "Hello world.~C~%" #\return) 

But is seems awkward to me. Surely I can somehow embed #\return into the very format string, like I can #\newline?

4 Answers 4

76
+100

Characters for return and linefeed

\r is the character #\return in Common Lisp.

\n is the character #\linefeed in Common Lisp.

The following ends the string "Hello world." with return and linefeed.

(format t "Hello world.~C~C" #\return #\linefeed) 

#\newline is whatever the platform uses as a line division. On Unix machines this is often the same as #\linefeed. On other platforms (Windows, Lisp Machines, ...) this could be different.

FORMAT control

The FORMAT control ~% prints a newline (!).

So

(format t "Hello world.~%") 

will print the newline that the operating system uses. CR or CRLF or LF. Depending on the platform this will be one or two characters.

So, on a Windows machine your

(format t "Hello world.~C~%" #\return) 

might actually print: #\return #\return #\linefeed. Which is THREE characters and not two. Windows uses CRLF for newlines. Unix uses LF. Old Mac OS (prior to Mac OS X) and Lisp Machines used CR for newlines.

Writing CRLF

If you really want to print CRLF, you have to do it explicitly. For example with:

(defun crlf (&optional (stream *standard-output*)) (write-char #\return stream) (write-char #\linefeed stream) (values)) 

FORMAT does not have special syntax for output of linefeed or carriage return characters.

Linebreaks in FORMAT control

Common Lisp allows multi-line strings. Thus we can use them as format controls:

Here you can see that the line break in the control string is also in the output:

CL-USER 77 > (format t "~%first line second line~%~%") first line second line NIL 

Here is an example where the ~@ FORMAT control keeps the linebreak, but removes the whitespace on the next line:

CL-USER 78 > (format t "~%first line~@ second line~%~%") first line second line NIL 
Sign up to request clarification or add additional context in comments.

4 Comments

In SBCL 1.0.22, CLISP 2.47 and Clozure CL 1.3 on Windows: (aref (format nil "~%") 0) returns #\Newline.
@Frank Shearar: and what does (length (format nil "~%")) produce? And what does it produce when you write it to a file? How long is the file?
1, 1 and 1 for the length. With (with-open-file (s #p"c:\\foo.txt" :direction :output :if-exists :supersede) (write-string (format nil "~%") s)), SBCL and CCL spat out a 1-byte file containing \#Newline. Clisp spat out a 1-byte file containing a #\Return!
@Frank Shearar: kind of funky, given that CRLF is the native line ending character sequence on Windows. Expect different results with some other Lisps (LispWorks, Allegro CL, Corman CL, ...). Btw., some implementations make it configurable - Allegro CL has some documentation about that...
6

First, in Common Lisp most characters, including return/newline, can be inserted directly into the string. The only character requiring escaping is the string delimiter.

There is also a library cl-interpol which provides a read macro to construct strings with more complex syntax, including special character escapes.

Comments

0

In case anyone just wants a string that ends with CRLF, I think this is a good way to do it:

(concatenate 'string "hello" '(#\return #\linefeed)) 

You can check in the REPL that it does produce the expected output:

CL-USER> (map 'list #'char-code (concatenate 'string "hello" '(#\return #\linefeed))) (104 101 108 108 111 13 10) 

Comments

0

Here's a set of trivial convenience functions which compile the other answers. Be aware that many older systems, such as Commodore 8-bits and 68K Apple Macintosh, used only Return (ASCII 13) for line endings. Thanks to @frank-shearar for mentioning the unexpected behavior of SBCL.

(defvar *crlf* (concatenate 'string #(#\Return #\Linefeed)) "DOS line ending sequence.") (defun dos-line (string) "Append the DOS line ending sequence to STRING." (concatenate 'string string *crlf*)) (defun dos-line-p (string) "Does STRING have the DOS line ending sequence?" (eql (- (length string) (length *crlf*)) ;; SEARCH works for any sequence, but probably isn't the fastest (search *crlf* string :from-end t))) (defun ensure-dos-line (string) "Ensure STRING ends with the DOS line ending sequence." (if (dos-line-p string) string (dos-line string))) ;;; Tests ;;; Just load the file like this: ;;; sbcl --script dos-lines.lisp | hd (let* ((s1 "Foo the bar!") (s2 (ensure-dos-line s1))) (assert (equal (format nil "~A~C~C" s1 (code-char 13) (code-char 10)) s2)) (princ s2)) 

Comments