I find it irritating that it's rather cumbersome to use literal string
in common lisp or elisp.
For instance, I can't simply copy and paste the regex that I cooked up
with The Regex Coach. It might not be that bad global replacing \ with
\\. But the result is harder to read in code.
But then for all the other strings that I need to deal with (for
instance, HTML) there are multiple characters that I need to escape.
Is it a good idea to use the Perl style string quoting in lisp ?
(defun lookup-term-char (char)
(case char
(#\{ #\})
(#\[ #\])
(#\< #\>)
(#\( #\))
(t char)))
(defun read-unescaped (stream term-char)
(let ((string (make-array 0 :element-type 'character :adjustable t
:fill-pointer 0)))
(loop for char = (read-char stream nil nil t)
until (char= char term-char) do
(vector-push-extend char string))
string))
(defun read-escaped (stream term-char)
(let ((string (make-array 0 :element-type 'character :adjustable t
:fill-pointer 0)))
(loop for char = (read-char stream nil nil t) do
(if (char= char #\\)
(vector-push-extend (read-char stream nil nil t) string)
(if (char= char term-char)
(return)
(vector-push-extend char string))))
string))
(defun read-heredoc-term-line (stream)
(let ((string (make-array 0 :element-type 'character :adjustable t
:fill-pointer 0)))
(loop for char = (read-char stream nil nil t)
until (char= char #\newline) do
(vector-push-extend char string))
string))
(defun read-heredoc (stream term-line)
(let ((out (make-string-output-stream)))
(loop for line = (read-line stream nil nil t)
until (string= line term-line) do
(write-sequence line out)
(write-char #\newline out))
(get-output-stream-string out)))
(defun |read-#q| (stream char arg)
"single q for string with no backslash escape.
double qq for string with backslash escape.
triple qqq for HEREDOC"
(declare (ignore char arg))
(let ((next-char (read-char stream nil nil t)))
(if (char= next-char #\q)
(let ((next-char (read-char stream nil nil t)))
(if (char= next-char #\q)
(read-heredoc stream (read-heredoc-term-line stream))
(read-escaped stream (lookup-term-char next-char))))
(read-unescaped stream (lookup-term-char next-char)))))
(set-dispatch-macro-character #\# #\q #'|read-#q|)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; with \ escape
(princ #qq!I say: "Hello, World\!"!)
=>
I say: "Hello, World!"
;; herestring
;; scsh uses #<<
http://www.scsh.net/docu/html/man-Z-H-2.html#node_sec_1.6.4
(defparameter *html-str*
#qqqHEREDOC
<html>
<head>
<script>
function lisp_rocks () {
alert ("\"It really is\"");
return false;
}
</script>
</head>
<body>
<a href= "return lisp_rocks()">Let me tell you</a>
</body>
</html>
HEREDOC
)
(princ *html-str* *HTTP-STREAM*)
;; Regular expression should be more readable
(cl-ppcre:register-groups-bind (fname lname (#'parse-integer date month
year))
("(\\w+)\\s+(\\w+)\\s+(\\d{1,2})\\.(\\d{1,2})\\.(\\d{4})" "Frank
Zappa 21.12.1940")
(list fname lname (encode-universal-time 0 0 0 date month year)))
;; This should be better
(cl-ppcre:register-groups-bind (fname lname (#'parse-integer date month
year))
(#q"(\w+)\s+(\w+)\s+(\d{1,2})\.(\d{1,2})\.(\d{4})" "Frank Zappa
21.12.1940")
(list fname lname (encode-universal-time 0 0 0 date month year)))
=>
("Frank" "Zappa" 1292918400)
···········@gmail.com writes:
> (defun |read-#q| (stream char arg)
> "single q for string with no backslash escape.
> double qq for string with backslash escape.
> triple qqq for HEREDOC"
Why are you ignoring the argument arg?
Wouldn't it be nicer to write: #q"abc" #3q"a\bc" #4qHERE
abc
HERE and #6qHERE
a\bc
HERE
You could process strings :
- with or without \
- with single char delimiter or multi-char delimiter
- with or without interpoling
- ...
or any combination, assigning different bits to the argument at will.
--
__Pascal Bourguignon__ http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.