From: ab talebi
Subject: Database with Lisp
Date: 
Message-ID: <3bf25f27.3130009@news.uio.no>
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

From: Vebjorn Ljosa
Subject: Re: Database with Lisp
Date: 
Message-ID: <cy3zo5p47tl.fsf@ljosa.com>
* ············@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
From: ab talebi
Subject: Re: Database with Lisp
Date: 
Message-ID: <3bf3a7f4.6382753@news.online.no>
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
From: Janis Dzerins
Subject: Re: Database with Lisp
Date: 
Message-ID: <87668dfgpj.fsf@asaka.latnet.lv>
············@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.