From: ···········@gmail.com
Subject: Perl style string quoting
Date: 
Message-ID: <1154177198.514973.184030@i3g2000cwc.googlegroups.com>
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)
From: Pascal Bourguignon
Subject: Re: Perl style string quoting
Date: 
Message-ID: <87psfozhsi.fsf@thalassa.informatimago.com>
···········@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.