【问题标题】:read words from a file into nested list in common lisp programming language用通用 lisp 编程语言将文件中的单词读入嵌套列表
【发布时间】:2019-10-18 12:06:58
【问题描述】:

我有一个名为 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 的新手,对这个问题有很多困惑。

【问题讨论】:

  • 请不要介意添加关于究竟是什么令人困惑的细节?另外,请查看 PCL 中的14. Files and File I/O(以及前面的章节也首先)。在这里,字符(例如用 Common Lisp 编写的 #\A#\Space(字符串由此类字符组成))和符号(具有名称的对象,它是一个字符串)之间存在混淆。这里he等是符号;您必须将问题拆分为子问题,例如:(1)如何从文件中一次读取一个字符,以及
  • (2) 如何从字符流等(状态机?)等中识别单词和段落。StackOverflow 最适合回答精确问题;也许编辑问题以澄清是什么阻止你现在尝试事情(糟糕的环境设置?缺乏关于在哪里找到文档的信息?如何运行程序?等等)

标签: lisp common-lisp nested-lists clisp


【解决方案1】:

没有任何依赖的解决方案

(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 的合适正则表达式包)

;; 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"))

【讨论】:

  • 非常感谢 :) 它对我的帮助更大
猜你喜欢
  • 1970-01-01
  • 2013-12-14
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 2017-10-18
  • 2010-11-15
  • 1970-01-01
相关资源
最近更新 更多