I have a file (account.txt) wich countains a small database of my
friends like this: (the data is ofcourse not correct)
=
name george
familyname bush
age 29
tlf. 555-432343
=
name cathrine
familyname bush
age 18
tlf 555-55432
=
name caroline
familyname bush
age 90
tlf 555-432112
=
the people are seperated by like-sign =
I have this function "lisp-friendly" that uses the function extract to
put this file in a more lisp-friendly way:
(defun extract (line)
(let ((list-of-letters '()) (position 0) (letter nil))
(loop
(multiple-value-setq (letter position)
(read-from-string line nil nil :start position))
(if (null letter)
(return (reverse list-of-letters))
(push letter list-of-letters)))))
(defun lisp-friendly (name)
(with-open-file (input name :direction :input)
(loop for line = (read-line input nil nil)
until (null line)
collect (extract line))))
(lisp-friendly "c:\account.txt")
((=) (NAME GEORGE) (FAMILYNAME BUSH) (AGE 29) (TLF. 555-432343) (=)
(NAME CATHRINE) (FAMILYNAME BUSH) (AGE 18) (TLF 555-55432) (=) (NAME
CAROLINE) (FAMILYNAME BUSH) (AGE 90) (TLF 555-432112) (=))
How can i rewrite "lisp-friendly" to treat the file with = as the
deliminator for different enteries. it should seperate enteries from
each other and put each of them in a list like this:
( ( (name george) (age 29) (tlf. 555-432343) )
( (name catherine) (age 18) (tlf 555-55432) )
etc
)
tnx
ab talebi
* ············@yahoo.com (ab talebi)
|
| How can i rewrite "lisp-friendly" to treat the file with = as the
| deliminator for different enteries. it should seperate enteries from
| each other and put each of them in a list like this:
|
| ( ( (name george) (age 29) (tlf. 555-432343) )
| ( (name catherine) (age 18) (tlf 555-55432) )
| etc
| )
Here's a way of doing it:
(defun read-address (stream)
(loop
for line = (read-line stream nil nil)
when (null line)
return stream
until (string-equal line "=")
collect
(multiple-value-bind (key position) (let ((*read-eval* nil))
(read-from-string line))
(loop
while (eq #\tab (char line position))
do (incf position)) ; skip multiple tabs
(list key
(subseq line position)))))
(defun read-addresses (pathname)
(with-open-file (stream pathname :direction :input)
(loop
for address = (read-address stream)
until (eq address stream)
collect address)))
It wasn't clear whether there is an equal sign after each entry,
before each entry, or between entries, so I assumed that there's one
_after_ each entry. Also notice that I chose to keep the values as
strings, and not try to read them.
--
Vebjorn Ljosa
On 14 Nov 2001 08:48:56 -0800, Vebjorn Ljosa <·····@ljosa.com> wrote:
>Here's a way of doing it:
>
>(defun read-address (stream)
> (loop
> for line = (read-line stream nil nil)
> when (null line)
> return stream
> until (string-equal line "=")
> collect
> (multiple-value-bind (key position) (let ((*read-eval* nil))
> (read-from-string line))
> (loop
> while (eq #\tab (char line position))
> do (incf position)) ; skip multiple tabs
> (list key
> (subseq line position)))))
>
>(defun read-addresses (pathname)
> (with-open-file (stream pathname :direction :input)
> (loop
> for address = (read-address stream)
> until (eq address stream)
> collect address)))
>
> Also notice that I chose to keep the values as
>strings, and not try to read them.
>
I think it is important that the values are kept and not converted to
stiring, i don't see any other reason why my program wouldn't work:
with this file that I keep in the variable database:
name george
familyname bush
age 29
tlf 555-432343
=
name cathrine
familyname bush
age 18
tlf 555-55432
=
name george
familyname mc donnald
age 32
tlf 555-22222
tlf 555-33333
=
(setf database "c:\account.txt")
(defun get-name (list)
(and (consp x) (eq (car x) 'name)))
(defun get-nr (list)
(and (consp x) (eq (car x) 'tlf)))
(defun get-tlf-nr (name)
(cond ((null name) nil)
((equal (cdar (remove-if-not #'get-name (read-adresses
database)))
name)
(cons (cdar (remove-if-not #'get-nr (read-addresses)))
(get-tlf-nr (cdr database))))))
get-tlf-nr is supposed to get a name as it's argument and go through
the account.txt file with car/cdr recursion and fetch the tlf nr.s of
all f.ex. georges multiple tlf nr.s is also possible
(get-tlf-nr (george)
==> ((555-432343) (555-22222)(555-33333))
I can not see what is wrong with this car/cdr recursion. can you see
it?
tnx
ab talebi
············@yahoo.com (ab talebi) writes:
> (defun extract (line)
> (let ((list-of-letters '()) (position 0) (letter nil))
> (loop
> (multiple-value-setq (letter position)
> (read-from-string line nil nil :start position))
> (if (null letter)
> (return (reverse list-of-letters))
> (push letter list-of-letters)))))
The variable names are misleading -- read-from-string in this case
returns symbols, not letters. Therefore I think you've got something
working not understanding how it works.
> How can i rewrite "lisp-friendly" to treat the file with = as the
> deliminator for different enteries. it should seperate enteries from
> each other and put each of them in a list like this:
You do just that -- collect the attribute/value pairs until you see a
=, in which case you put pairs collected so far in the result
list. Should be a simple extension to the lisp-friendly function.
--
Janis Dzerins
Eat shit -- billions of flies can't be wrong.