Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Function to output more readable

4 views
Skip to first unread message

Cecil Westerhof

unread,
Jan 4, 2010, 7:58:17 AM1/4/10
to
Based on PCL I have the following function to save my 'database':
(defun save-db (db filename)
(with-open-file (out filename
:direction :output
:if-exists :supersede)
(with-standard-io-syntax
(print db out))))

This gives:
((:|NAME| "Salate de vinete" :|INGREDIENTS| ((:|QUANTITY| "10" :|TYPE| "stuk" :|INGREDIENT| "grote aubergines") (:|QUANTITY| "30" :|TYPE| "stuk" :|INGREDIENT| "gedroogde en gemalen pepers") (:|QUANTITY| "3" :|TYPE| "stuk" :|INGREDIENT| "ui") (:|QUANTITY| "1" :|TYPE| "eetlepel" :|INGREDIENT| "knoflook") (:|QUANTITY| "2" :|TYPE| "eetlepels" :|INGREDIENT| "zout") (:|QUANTITY| " " :|TYPE| " " :|INGREDIENT| "olie")) :|STEPS| ("Doe de aubergines zonder voorverwarmen 50 minuten in de oven op 200 graden. (Ze moeten zwart en zacht zijn en het vel moet makkelijk loslaten.)" "Vel eraf halen en uit laten lekken." "Pureren tot en met knoflook." "Zout en olie toevoegen.")) (:|NAME| "Kwarktaart" :|INGREDIENTS| ((:|QUANTITY| "1" :|TYPE| "kilo" :|INGREDIENT| "kwark") (:|QUANTITY| "300" :|TYPE| "gram" :|INGREDIENT| "suiker") (:|QUANTITY| "4" :|TYPE| "stuk" :|INGREDIENT| "eieren") (:|QUANTITY| "8" :|TYPE| "eetlepels" :|INGREDIENT| "bloem") (:|QUANTITY| "5" :|TYPE| "eetlepels" :|INGREDIENT| "citroensap") (:|QUANTITY| "2" :|TYPE| "stuk" :|INGREDIENT| "uitgeperste sinasappels i.p.v. citroensap") (:|QUANTITY| "100" :|TYPE| "gram" :|INGREDIENT| "cacao")) :|STEPS| ("Meng een voor een alle ingredienten." "Bak 1 uur op 150 graden." "Half uur in de oven laten staan." "Af laten koelen." "Minimaal 3 uur in de koelkast.")) (:|NAME| "Appel-kaneel muffin" :|INGREDIENTS| ((:|QUANTITY| "3" :|TYPE| "stuk" :|INGREDIENT| "eieren") (:|QUANTITY| "300" :|TYPE| "gram" :|INGREDIENT| "suiker") (:|QUANTITY| "1" :|TYPE| "eetlepel" :|INGREDIENT| "kaneel") (:|QUANTITY| "1" :|TYPE| "theelepel" :|INGREDIENT| "zout") (:|QUANTITY| "250" :|TYPE| "gram" :|INGREDIENT| "roomboter") (:|QUANTITY| "500" :|TYPE| "gram" :|INGREDIENT| "bulgaarse yoghurt") (:|QUANTITY| "400" :|TYPE| "gram" :|INGREDIENT| "zelfrijzend bakmeel") (:|QUANTITY| "6" :|TYPE| "stuk" :|INGREDIENT| "appels (in kleine stukjes)")) :|STEPS| ("Meng een voor een alle ingredienten." "Muffin vormen voor 2/3 vullen." "Bak 20 minuten op 200 graden.")) (:|NAME| "Brownies" :|INGREDIENTS| ((:|QUANTITY| "5" :|TYPE| "stuk" :|INGREDIENT| "eieren") (:|QUANTITY| "350" :|TYPE| "gram" :|INGREDIENT| "suiker") (:|QUANTITY| "175" :|TYPE| "gram" :|INGREDIENT| "boter (gesmolten)") (:|QUANTITY| "1" :|TYPE| "eetlepel" :|INGREDIENT| "vanille essence") (:|QUANTITY| "175" :|TYPE| "gram" :|INGREDIENT| "bloem") (:|QUANTITY| "100" :|TYPE| "gram" :|INGREDIENT| "cacao") (:|QUANTITY| "100" :|TYPE| "gram" :|INGREDIENT| "(walnoten)") (:|QUANTITY| "100" :|TYPE| "gram" :|INGREDIENT| "(kokos)") (:|QUANTITY| "2" :|TYPE| "stuk" :|INGREDIENT| "(bananen)") (:|QUANTITY| "100" :|TYPE| "gram" :|INGREDIENT| "(hazelnoten)")) :|STEPS| ("Meng een voor een alle ingredienten." "Bak 25 minuten op 175 graden.")))

This is okay when only saving and loading, but I have the quirk that I
also like to do visual inspections. Of course I could try to write a
function for this, but I would not be surprised if there is already
something which outputs something like:
(
(:|NAME| "Salate de vinete"
:|INGREDIENTS|
(
(:|QUANTITY| "10"
:|TYPE| "stuk"
:|INGREDIENT| "grote aubergines")
(:|QUANTITY| "30"
:|TYPE| "stuk"
:|INGREDIENT| "gedroogde en gemalen pepers")
(:|QUANTITY| "3"
:|TYPE| "stuk"
:|INGREDIENT| "ui")
(:|QUANTITY| "1"
:|TYPE| "eetlepel"
:|INGREDIENT| "knoflook")
(:|QUANTITY| "2"
:|TYPE| "eetlepels"
:|INGREDIENT| "zout")
(:|QUANTITY| " "
:|TYPE| " "
:|INGREDIENT| "olie"))
:|STEPS|
("Doe de aubergines zonder voorverwarmen 50 minuten in de oven op
200 graden. (Ze moeten zwart en zacht zijn en het vel moet
makkelijk loslaten.)"
"Vel eraf halen en uit laten lekken."
"Pureren tot en met knoflook."
"Zout en olie toevoegen."))
(:|NAME| "Kwarktaart"
:|INGREDIENTS|
.
.
.

So my questions is: is there something to output lisp structures in a
human and lisp readable way?

--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

Tamas K Papp

unread,
Jan 4, 2010, 8:17:38 AM1/4/10
to
On Mon, 04 Jan 2010 13:58:17 +0100, Cecil Westerhof wrote:

> Based on PCL I have the following function to save my 'database':
> (defun save-db (db filename)
> (with-open-file (out filename
> :direction :output
> :if-exists :supersede)
> (with-standard-io-syntax
> (print db out))))
>
> This gives:
> ((:|NAME| "Salate de vinete" :|INGREDIENTS| ((:|QUANTITY| "10" :|TYPE|
> "stuk" :|INGREDIENT| "grote aubergines") (:|QUANTITY| "30" :|TYPE|

> ...


>
> So my questions is: is there something to output lisp structures in a
> human and lisp readable way?

Yes, see pprint, and maybe Section 22.2: The Lisp Pretty Printer in
the CLHS for full control of a zillion features (but (pprint db out)
should do pretty much what you want). Happy baking :-)

HTH,

Tamas

Norbert_Paul

unread,
Jan 4, 2010, 8:22:24 AM1/4/10
to
.. or else

(let ((*PRINT-PRETTY* T))
(put-your-printig-statements-here) )


[HyperSpec/Body/var_stprint-prettyst.html]

This might be what you were looking for.

Regards
Norbert

Cecil Westerhof wrote:
[...]

Cecil Westerhof

unread,
Jan 4, 2010, 8:40:23 AM1/4/10
to

Using pprint instead of print gives:


((:|NAME| "Salate de vinete" :|INGREDIENTS|
((:|QUANTITY| "10" :|TYPE| "stuk" :|INGREDIENT| "grote aubergines")

(:|QUANTITY| "30" :|TYPE| "stuk" :|INGREDIENT|
"gedroogde en gemalen pepers")
(:|QUANTITY| "3" :|TYPE| "stuk" :|INGREDIENT| "ui")
(:|QUANTITY| "1" :|TYPE| "eetlepel" :|INGREDIENT| "knoflook")
(:|QUANTITY| "2" :|TYPE| "eetlepels" :|INGREDIENT| "zout")
(:|QUANTITY| " " :|TYPE| " " :|INGREDIENT| "olie"))
:|STEPS|
("Doe de aubergines zonder voorverwarmen 50 minuten in de oven op 200 graden. (Ze moeten zwart en zacht zijn en het vel moet makkelijk loslaten.)"
"Vel eraf halen en uit laten lekken." "Pureren tot en met knoflook."
"Zout en olie toevoegen."))

.
.
.

I would prefer that:


((:|NAME| "Salate de vinete" :|INGREDIENTS|
((:|QUANTITY| "10" :|TYPE| "stuk" :|INGREDIENT| "grote aubergines")

would be output like:


((:|NAME| "Salate de vinete"
:|INGREDIENTS|
((:|QUANTITY| "10" :|TYPE| "stuk" :|INGREDIENT| "grote aubergines")

But it does not hurt enough to make work off it. (At least not for the
moment.) It is quit readable. Maybe when I get bored, I'll try to fine
tune it.

Thanks for the tip.

Pascal J. Bourguignon

unread,
Jan 4, 2010, 11:27:12 AM1/4/10
to
Cecil Westerhof <Ce...@decebal.nl> writes:

I have an emacs lisp function to cut such single line sexps.
Basically, it just inserts a newline in front of each keyword, and
between any sublist.


(defun pretty-print-lisp-structures (start end)
"Given a sexp (or xml) formatted on a single line, inserts newlines and indent-region it."
(interactive "r")
(let ((start (let ((m (make-marker))) (set-marker m start)))
(end (let ((m (make-marker))) (set-marker m end))))
(unwind-protect
(progn
(narrow-to-region start end)
(remove-all-properties)
(let ((output '()))
(dolines (lstart lend)
(goto-char lstart)
(if (looking-at "\\([^(\n]*\\)\\(([^\n]*\\)$")
(push (list (match-string 1) (match-string 2)) output)
(push (buffer-substring-no-properties lstart lend) output)))
(delete-region start end) ; no erase-buffer because of narrow-to-region
(message (format "output = %S" (reverse output)))
(dolist (line (reverse output))
(if (listp line)
(destructuring-bind (prefix sexp) line
(let ((sexp (with-temp-buffer
(insert sexp)
(let ((start (point-min)))
(goto-char start)
(while (re-search-forward "::" nil t)
(delete-region (match-beginning 0) (match-end 0))
(insert "//"))

(goto-char start)
(while (re-search-forward "<" nil t)
(delete-region (match-beginning 0) (match-end 0))
(insert "("))

(goto-char start)
(while (re-search-forward ">" nil t)
(delete-region (match-beginning 0) (match-end 0))
(insert ")"))

(goto-char start)
(while (re-search-forward ") \\. (" nil t)
(delete-region (match-beginning 0) (match-end 0))
(insert ")\n. ("))

(goto-char start)
(while (re-search-forward ") *(" nil t)
(delete-region (match-beginning 0) (match-end 0))
(insert ")\n("))

(goto-char start)
(while (re-search-forward " *:" nil t)
(delete-region (match-beginning 0) (match-end 0))
(insert "\n:")))
(let ((backup (buffer-substring-no-properties (point-min) (point-max))))
(handler-case
(let ((lisp-mode-hook '())
(emacs-lisp-mode-hook '())
(common-lisp-mode-hook '()))
(lisp-mode)
(indent-region (point-min) (point-max))
(buffer-substring-no-properties (point-min) (point-max)))
(error ()
backup))))))
(insert ";; " (string-trim "\n" prefix) "\n\n" sexp "\n\n")))
(insert ";; " line "\n")))))
(widen)
(set-marker start nil)
(set-marker end nil))))


On your example sexp, it gives this:


--
__Pascal Bourguignon__ http://www.informatimago.com/

Cecil Westerhof

unread,
Jan 4, 2010, 12:21:05 PM1/4/10
to
p...@informatimago.com (Pascal J. Bourguignon) writes:

>> So my questions is: is there something to output lisp structures in a
>> human and lisp readable way?
>
> I have an emacs lisp function to cut such single line sexps.
> Basically, it just inserts a newline in front of each keyword, and
> between any sublist.
>

[cut function]


>
> On your example sexp, it gives this:
>
>
> ((:|NAME| "Salate de vinete"
> :|INGREDIENTS| ((:|QUANTITY| "10"
> :|TYPE| "stuk"
> :|INGREDIENT| "grote aubergines")
> (:|QUANTITY| "30"
> :|TYPE| "stuk"
> :|INGREDIENT| "gedroogde en gemalen pepers")
> (:|QUANTITY| "3"
> :|TYPE| "stuk"
> :|INGREDIENT| "ui")
> (:|QUANTITY| "1"
> :|TYPE| "eetlepel"
> :|INGREDIENT| "knoflook")
> (:|QUANTITY| "2"
> :|TYPE| "eetlepels"
> :|INGREDIENT| "zout")
> (:|QUANTITY| " "
> :|TYPE| " "
> :|INGREDIENT| "olie"))
> :|STEPS| ("Doe de aubergines zonder voorverwarmen 50 minuten in de oven op 200 graden. (Ze moeten zwart en zacht zijn en het vel moet makkelijk loslaten.)" "Vel eraf halen en uit laten lekken." "Pureren tot en met knoflook." "Zout en olie toevoegen."))

That looks quit good. Maybe it would be nice to have quantity start on
its own line and the list of steps be split. It looks like I have to
merge pprint and your function.

0 new messages