From: John Thingstad
Subject: Improve code
Date: 
Message-ID: <f75u91$8c7$1@news.get.no>
I am working on a blog program working with hunchentoot and clsql.
I am using a applet called editize which edits a subset of HTML and returns 
it. externally it works as a input text field. The problem is that it need 
the entire HTML file input as a string.
editize.display('document')
This poses a problem because CR LF RT \ " and ' need special handeling.
This function does that.:

(defun script-string (text)
  (coerce
   (iter (for char in-string text)
     (cond
      ((char= char #\')
       (collect #\\)
       (collect #\'))
      ((char= char #\")
       (collect #\\)
       (collect #\"))
      ((char= char #\\)
       (collect #\\)
       (collect #\\))
      (t
       (unless (or (char= char #\NewLine)
                   (char= char #\Return)
                   (char= char #\LineFeed))
         (collect char)))))
     'string))

As you can see it is a ugly thing..
Is there a better way of doing this? 

From: ·······@gmx.net
Subject: Re: Improve code
Date: 
Message-ID: <1184277345.539191.255870@o61g2000hsh.googlegroups.com>
On 12 Jul., 21:10, "John Thingstad" <··············@chello.no> wrote:
> I am working on a blog program working with hunchentoot and clsql.
> I am using a applet called editize which edits a subset of HTML and returns
> it. externally it works as a input text field. The problem is that it need
> the entire HTML file input as a string.
> editize.display('document')
> This poses a problem because CR LF RT \ " and ' need special handeling.
> This function does that.:
....
>
> As you can see it is a ugly thing..
> Is there a better way of doing this?

I like this way better, you decide if you agree with me :)

(defun script-string2 (text)
  (let ((escape-chars (list #\'
			    #\"
			    #\\))
	(remove-chars (list #\Newline
			    #\Return
			    #\Linefeed)))
    (iter (for char in-string text)
	  (when (member char escape-chars :test #'char=)
	    (collect #\\ result-type 'string))
	  (unless (member char remove-chars :test #'char=)
	    (collect char result-type 'string)))))

Blessings,
Simon
From: Ari Johnson
Subject: Re: Improve code
Date: 
Message-ID: <m2hco943no.fsf@hermes.theari.com>
·······@gmx.net writes:

> On 12 Jul., 21:10, "John Thingstad" <··············@chello.no> wrote:
>> I am working on a blog program working with hunchentoot and clsql.
>> I am using a applet called editize which edits a subset of HTML and returns
>> it. externally it works as a input text field. The problem is that it need
>> the entire HTML file input as a string.
>> editize.display('document')
>> This poses a problem because CR LF RT \ " and ' need special handeling.
>> This function does that.:
> ....
>>
>> As you can see it is a ugly thing..
>> Is there a better way of doing this?
>
> I like this way better, you decide if you agree with me :)
>
> (defun script-string2 (text)
>   (let ((escape-chars (list #\'
> 			    #\"
> 			    #\\))
> 	(remove-chars (list #\Newline
> 			    #\Return
> 			    #\Linefeed)))
>     (iter (for char in-string text)
> 	  (when (member char escape-chars :test #'char=)
> 	    (collect #\\ result-type 'string))
> 	  (unless (member char remove-chars :test #'char=)
> 	    (collect char result-type 'string)))))

Why not just be generic and overboard all at once?  Here's a start.

; Exercise for the reader: get rid of the global variable
(defvar *character-substitutions* (make-hash-table))

(defun backslash-escape (character)
  (concatenate 'string "\\" (string character)))

(defun ignore-character (character)
  (declare (ignore character))
  "")

; This one is just for fun; a more general HTML entity conversion
; would be even more exciting
(defun hex-escape (character)
  (concatenate 'string "&#" (format nil "~x" (char-code character)) ";"))

; See above for the homework assignment
(loop :for c :in '(#\' #\" #\\)
  :do (setf (gethash c *character-substitutions*) 'backslash-escape))

; Likewise
(loop :for c :in '(#\Newline #\Return #\Linefeed)
  :do (setf (gethash c *character-substitutions*) 'ignore-character))

; As long as we're not optimizing anything... ;)
(defun sanitize-string (string)
  (apply 'concatenate 'string
    (loop :for c :across string
      :collect (let ((function (gethash c *character-substitutions*)))
                 (if function
                   (funcall function c)
                   (string c))))))
From: Rob St. Amant
Subject: Re: Improve code
Date: 
Message-ID: <f763ko$c3b$1@blackhelicopter.databasix.com>
"John Thingstad" <··············@chello.no> writes:

> I am working on a blog program working with hunchentoot and clsql.
> I am using a applet called editize which edits a subset of HTML and returns 
> it. externally it works as a input text field. The problem is that it need 
> the entire HTML file input as a string.
> editize.display('document')
> This poses a problem because CR LF RT \ " and ' need special handeling.
> This function does that.:
>
> (defun script-string (text)
>   (coerce
>    (iter (for char in-string text)
>      (cond
>       ((char= char #\')
>        (collect #\\)
>        (collect #\'))
>       ((char= char #\")
>        (collect #\\)
>        (collect #\"))
>       ((char= char #\\)
>        (collect #\\)
>        (collect #\\))
>       (t
>        (unless (or (char= char #\NewLine)
>                    (char= char #\Return)
>                    (char= char #\LineFeed))
>          (collect char)))))
>      'string))
>
> As you can see it is a ugly thing..
> Is there a better way of doing this? 

I don't know if expressing the character substitutions in a
declarative form would make things prettier, but I do wonder about
skipping over the end-of-line characters--does that munge separate
words together?
From: Dan Bensen
Subject: Re: Improve code
Date: 
Message-ID: <f76ibs$cdn$1@wildfire.prairienet.org>
John Thingstad wrote:
 >      (cond ...
 > Is there a better way of doing this?

   (case char
     ((#\' #\" #\\) (collect #\\) (collect char))
     ((#\NewLine #\Return #\LineFeed))
     (t (collect char)))

(not tested)

-- 
Dan
www.prairienet.org/~dsb/
From: John Thingstad
Subject: Re: Improve code
Date: 
Message-ID: <f77pdk$mq$1@news.get.no>
"Dan Bensen" <··········@cyberspace.net> skrev i melding 
·················@wildfire.prairienet.org...
> John Thingstad wrote:
> >      (cond ...
> > Is there a better way of doing this?
>
>   (case char
>     ((#\' #\" #\\) (collect #\\) (collect char))
>     ((#\NewLine #\Return #\LineFeed))
>     (t (collect char)))
>
> (not tested)
>
> -- 
> Dan
> www.prairienet.org/~dsb/

That is beautiful! Just what I wanted.
Thanks! 
From: Pillsy
Subject: Re: Improve code
Date: 
Message-ID: <1184299010.306217.307780@g4g2000hsf.googlegroups.com>
On Jul 12, 3:10 pm, "John Thingstad" <··············@chello.no> wrote:
[...]
> (defun script-string (text)
>   (coerce
>    (iter (for char in-string text)
>      (cond
>       ((char= char #\')
>        (collect #\\)
>        (collect #\'))
>       ((char= char #\")
>        (collect #\\)
>        (collect #\"))
>       ((char= char #\\)
>        (collect #\\)
>        (collect #\\))
>       (t
>        (unless (or (char= char #\NewLine)
>                    (char= char #\Return)
>                    (char= char #\LineFeed))
>          (collect char)))))
>      'string))

> As you can see it is a ugly thing..
> Is there a better way of doing this?

I'm sorry if this is a dumb question, but do you just want to drop the
newlines and such, or turn them into whitespace?

Cheers
Pillsy
From: John Thingstad
Subject: Re: Improve code
Date: 
Message-ID: <f77pbn$ln$1@news.get.no>
>
> I'm sorry if this is a dumb question, but do you just want to drop the
> newlines and such, or turn them into whitespace?
>
> Cheers
> Pillsy
>

In that implementation I just dropped them completely.
As Editize always groups elements in HTML tags that didn't represent
a problem. As it works well generatlly I changed it to produce a #\space
instead. Using the suggestion above it becomes:

(defun script-string (text)
  (coerce
   (iter (for char in-string text)
     (case char
       ((#\' #\" #\\) (collect #\\) (collect char))
       ((#\Newline #\Return #\Newline) (collect #\Space))
       (t (collect char))))
   'string))
From: Rainer Joswig
Subject: Re: Improve code
Date: 
Message-ID: <joswig-63C7AC.21153812072007@news-europe.giganews.com>
In article <············@news.get.no>,
 "John Thingstad" <··············@chello.no> wrote:

> I am working on a blog program working with hunchentoot and clsql.
> I am using a applet called editize which edits a subset of HTML and returns 
> it. externally it works as a input text field. The problem is that it need 
> the entire HTML file input as a string.
> editize.display('document')
> This poses a problem because CR LF RT \ " and ' need special handeling.
> This function does that.:
> 
> (defun script-string (text)
>   (coerce
>    (iter (for char in-string text)
>      (cond
>       ((char= char #\')
>        (collect #\\)
>        (collect #\'))
>       ((char= char #\")
>        (collect #\\)
>        (collect #\"))
>       ((char= char #\\)
>        (collect #\\)
>        (collect #\\))
>       (t
>        (unless (or (char= char #\NewLine)
>                    (char= char #\Return)
>                    (char= char #\LineFeed))
>          (collect char)))))
>      'string))
> 
> As you can see it is a ugly thing..

What do you think is ugly about it?
What would you like to improve?

> Is there a better way of doing this?

-- 
http://lispm.dyndns.org
From: Thomas F. Burdick
Subject: Re: Improve code
Date: 
Message-ID: <1184311980.561574.65290@e9g2000prf.googlegroups.com>
On Jul 12, 9:10 pm, "John Thingstad" <··············@chello.no> wrote:
> I am working on a blog program working with hunchentoot and clsql.
> I am using a applet called editize which edits a subset of HTML and returns
> it. externally it works as a input text field. The problem is that it need
> the entire HTML file input as a string.
> editize.display('document')
> This poses a problem because CR LF RT \ " and ' need special handeling.
> This function does that.:
>
> (defun script-string (text)
>   (coerce
>    (iter (for char in-string text)
>      (cond
>       ((char= char #\')
>        (collect #\\)
>        (collect #\'))
>       ((char= char #\")
>        (collect #\\)
>        (collect #\"))
>       ((char= char #\\)
>        (collect #\\)
>        (collect #\\))
>       (t
>        (unless (or (char= char #\NewLine)
>                    (char= char #\Return)
>                    (char= char #\LineFeed))
>          (collect char)))))
>      'string))
>
> As you can see it is a ugly thing..
> Is there a better way of doing this?

Yes, that's pretty ugly, with the repeated code and the call to
coerce.  I'd have written it like this (making the change of replacing
whitespace with whitespace instead of eliminating it):

  (with-output-to-string (out)
    (loop for char across string
          if (find char #(#\' #\" #\\))
            do (write-char #\\ out) (write-char char out)
          else if (find char #(#\Newline #\Return #\Linefeed))
            do (write-char #\Space out)
          else do (write-char char out)))
From: John Thingstad
Subject: Re: Improve code
Date: 
Message-ID: <f77qaj$1ie$1@news.get.no>
>
> Yes, that's pretty ugly, with the repeated code and the call to
> coerce.  I'd have written it like this (making the change of replacing
> whitespace with whitespace instead of eliminating it):
>
>  (with-output-to-string (out)
>    (loop for char across string
>          if (find char #(#\' #\" #\\))
>            do (write-char #\\ out) (write-char char out)
>          else if (find char #(#\Newline #\Return #\Linefeed))
>            do (write-char #\Space out)
>          else do (write-char char out)))
>
>

How about this? Combining all of the feedback I get this.
It seems the best solution.

(defun script-string (text)
  (with-output-to-string (out)
    (iter (for char in-string text)
      (case char
        ((#\' #\" #\\) (write-char #\\ out) (write-char char out))
        (((#\Newline #\Return #\Linefeed)) (write-char #\Space out))
        (t (write-char char out))))))

Thaks. 
From: Wade Humeniuk
Subject: Re: Improve code
Date: 
Message-ID: <m21wfcqsmc.fsf@telus.net.no.spam>
In real code (with an eye to extensibility and flexibility) I tend to
do this,

(defmethod script-write ((obj character) stream)
  (write-char obj stream))
(defmethod script-write ((obj (eql #\Newline)) stream)
  (write-char #\Space stream))
(defmethod script-write ((obj (eql #\Return)) stream)
  (write-char #\Space stream))
(defmethod script-write ((obj (eql #\Linefeed)) stream)
  (write-char #\Space stream))
(defmethod script-write ((obj (eql #\')) stream)
  (write-char #\\ stream)
  (write-char obj stream))
(defmethod script-write ((obj (eql #\")) stream)
  (write-char #\\ stream)
  (write-char obj stream))
(defmethod script-write ((obj (eql #\\)) stream)
  (write-char #\\ stream)
  (write-char obj stream))

(defmethod script-write ((obj string) stream)
  (loop for c across obj do (script-write c stream)))

(defun script-string (text)
  (with-output-to-string (out)
    (script-write text out)))

script-string then becomes a trivial use of script-write
on a string-output-stream.  Your example is pretty simple, but...

there is always a but.

Wade
From: Wade Humeniuk
Subject: Re: Improve code
Date: 
Message-ID: <m2wsx4pdef.fsf@telus.net.no.spam>
In case anyone is wondering, what extensibility??

Just by adding

(defmethod script-write ((obj list) stream)
  (loop for elt in obj do (script-write elt stream)))
(defmethod script-write ((obj number) stream)
  (write obj :stream stream))

We now have

CL-USER> (script-string '("hello " 10 " wade's \"test\"
"))
"hello 10 wade\\'s \\\"test\\\" "
CL-USER> 

Which one may consider very useful.

Wade
From: Saurabh Nanda
Subject: Re: Improve code
Date: 
Message-ID: <f7778v$28h$1@registered.motzarella.org>
Wouldn't a series of regex replaces work for you? For example:

(cl-ppcre:regex-replace-all "'" "friend's friend" "\\\\'")

Saurabh.