首页 > 解决方案 > 用通用 lisp 编程语言将文件中的单词读入嵌套列表

问题描述

我有一个名为 test.txt 的文件,它包含

"hello this is a test file"

我想从文件中读取它,以便每个单词代表字符列表,每个段落代表单词列表,这意味着我想将它们存储到嵌套列表中,例如:

(list(list (h e l l o)) (list(t h i s))(list(i s)) (list(a)) (list(t e s t)) (list(f i l e))))

我是 lisp 的新手,对这个问题有很多困惑。

标签: lispcommon-lispnested-listsclisp

解决方案


没有任何依赖的解决方案

(defun split (l &key (separators '(#\Space #\Tab #\Newline)) (acc '()) (tmp '()))
  (cond ((null l) (nreverse (if tmp (cons (nreverse tmp) acc) acc)))
        ((member (car l) separators)
         (split (cdr l) :separators separators 
                        :acc (if tmp (cons (nreverse tmp) acc) acc)
                        :tmp '()))
        (t 
         (split (cdr l) :separators separators
                        :acc acc
                        :tmp (cons (car l) tmp)))))

(defun read-file-lines (file-path)
  (with-open-file (f file-path :direction :input)
    (loop for line = (read-line f nil)
          while line
          collect line)))

(defun read-file-to-word-characters (file-path)
  (mapcan (lambda (s) (split (coerce s 'list))) 
          (read-file-lines file-path)))

(read-file-to-word-characters "~/test.lisp.txt")
;; ((#\h #\e #\l #\l #\o) (#\t #\h #\i #\s) (#\i #\s) (#\a) (#\t #\e #\s #\t)
;; (#\f #\i #\l #\e))

将字符转换为单字母字符串:

;; apply to elements of nested list (= a tree) the conversion function `string`
(defun map-tree (fn tree)
  (cond ((null tree) '())
        ((atom tree) (funcall fn tree))
        (t (mapcar (lambda (branch) (map-tree fn branch)) tree))))

(map-tree #'string (read-file-to-word-characters "~/test.lisp.txt"))
;; (("h" "e" "l" "l" "o") ("t" "h" "i" "s") ("i" "s") ("a") ("t" "e" "s" "t")
;;  ("f" "i" "l" "e"))

“~/test.lisp.txt”的内容:

hello this
is a test file

使用 cl-ppcre 的解决方案(Edi Weitz's congenial regex package)

;; look here in an answer how to use cl-ppcre:split
;; https://stackoverflow.com/questions/15393797/lisp-splitting-input-into-separate-strings
(ql:quickload :cl-ppcre)

(defun read-file-lines (file-path)
  (with-open-file (f file-path :direction :input)
    (loop for line = (read-line f nil)
          while line
          collect line)))

(defun string-to-words (s) (cl-ppcre:split "\\s+" s))
(defun to-single-characters (s) (coerce s 'list))

(defun read-file-to-character-lists (file-path)
  (mapcan (lambda (s) 
            (mapcar #'to-single-characters
                    (string-to-words s)))
          (read-file-lines file-path)))

(read-file-to-character-lists "~/test.lisp.txt")
;; ((#\h #\e #\l #\l #\o) (#\t #\h #\i #\s) (#\i #\s) (#\a) (#\t #\e #\s #\t)
;;  (#\f #\i #\l #\e))

;; or use above's function:
(map-tree #'string (read-file-to-character-lists "~/test.lisp.txt"))
;; (("h" "e" "l" "l" "o") ("t" "h" "i" "s") ("i" "s") ("a") ("t" "e" "s" "t")
;;  ("f" "i" "l" "e"))


;; or:
(defun to-single-letter-strings (s) (cl-ppcre:split "\\s*" s))

(defun read-file-to-letter-lists (file-path)
  (mapcan (lambda (s) 
            (mapcar #'to-single-letter-strings
                    (string-to-words s)))
          (read-file-lines file-path)))

(read-file-to-letter-lists "~/test.lisp.txt")
;; (("h" "e" "l" "l" "o") ("t" "h" "i" "s") ("i" "s") ("a") ("t" "e" "s" "t")
;; ("f" "i" "l" "e"))

推荐阅读