【问题标题】:Read a file and convert into an n-ary tree based nested list in Common Lisp?在 Common Lisp 中读取文件并转换为基于 n 元树的嵌套列表?
【发布时间】:2016-08-17 09:03:12
【问题描述】:

对于我的一个项目,我正在尝试使用 Common Lisp,特别是 SBCL(在此过程中,学习它。这是动机之一。)

我需要阅读一个包含问题和答案的文件,基本上就像一个主要包含多项选择问题答案的标准化测试。

我有一些用“|”之类的部分标记标记的示例问题用于开始和“//s”用于和部分。试卷将具有这样的层次结构:部分 -> 多个子部分 -> 每个子部分有多个问题 -> 每个问题将有多个答案,其中一个是正确的。

这个层次结构最终需要转换成一个json文件,推送到一个android app上供下游消费。

STEP-1:阅读源测试文件后,我的列表将如下所示:

(("Test" . "t")
 ("0.1" . "v")
 ("today" . "d")
 ("General Knowledge" . "p")
 ("Science" . "s")
 ("what is the speed of light in miles per second?" . "q")
 ("Choose the best answer from the following" . "i")
 ("MCQ question" . "n")
 ("186000" . "c")
 ("286262" . "w")
 ("200000" . "w"))

[PS.1]请参阅帖子末尾的图例,了解 h、p、t、v 等 cdar 值的解释, p>

[PS.2]本文末尾附上的源文件示例

consed 对中的每辆汽车代表内容,cdr 代表部分 - 这将对应于一个部分、子部分或一个问题等,

STEP-2:最后我需要把它转换成下面的格式——一个alist——

((:QANDA . "Test") (:VERSION . "0.1") (:DATE . "today")
 (:SECTION
  ((:TITLE . "General Knowledge")
   (:SUBSECTION
    ((:SSTITLE . "Science")
     (:QUESTION
      ((:QUESTION . "what is the speed of light in miles per second?")
       (:DIRECTIONS . "Choose the best answer from the following")
       (:TYPE . "MCQ question")
       (:CHOICES ((:CHOICE . "186000") (:CORRECT . "Y"))
        ((:CHOICE . "286000") (:CORRECT . "N"))
        ((:CHOICE . "200000") (:CORRECT . "N"))))))))))

由 cl-json 使用。

STEP-3: cl-json 会从中生成一个合适的 json。

json 将如下所示:

 {
  "qanda": "Test",
  "version": "0.1",
  "date": "today",
  "section": [
    {
      "title": "General Knowledge",
      "subsection": [
        {
          "sstitle": "Science",
          "question": [
            {
              "question": "what is the speed of light in miles per second?",
              "Directions": "Choose the best answer from the following",
              "type": "MCQ question",
              "choices": [
                {
                  "choice": "186000",
                  "Correct": "Y"
                },
                {
                  "choice": "286000",
                  "Correct": "N"
                },
                {
                  "choice": "200000",
                  "Correct": "N"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

我已成功读取源文件,生成 consed 对列表。我正在努力的地方是创建这个嵌套列表,如上所示,以将其提供给 cl-json。

经过一番挣扎后,我意识到这或多或少像一个 n 叉树问题。

这是我的问题:

a) 构建试卷源文件的这种 n 叉树表示的正确方法是什么?

b) 或者是否有更好或更简单的数据结构来表示这一点?

这是我尝试过的,其中 qtree 最初是 '() 而 kvlist 是上面显示的 consed 对列表。这是一个不完整的代码,因为我尝试了 push.、consing 和 nconc(结果不可靠)。

步骤 1 和步骤 3 都可以。第2步是我需要帮助的地方。问题是如何通过迭代kvlist来连续添加子节点,并在有多个父节点时找到合适的父节点来添加子节点(例如,向第二个子节点添加问题-部分):
(defun build-qtree (qtree kvlist)
  (cond
    ((eq '() kvlist) qtree)
    ((equal "h" (cdar kvlist))
     (push (car kvlist) qtree)
     (build-qtree qtree (cdr kvlist)))
    ((equal "p" (cdar kvlist))
     (nconc (last qtree) '((:SECTION))))
    (t
     (qtree)))) 

[PS.1] 图例:这将在条件分支中使用,也可以是defstruct或字典类型的列表等,

t - 标题,v - 版本,d - 日期,p - 部分,s - 子部分,q - 问题,i - 说明,n - 问题类型,c - 正确答案,w - 错误答案

[PS.2]源文件:

|Test//t
|0.1//v
|today//d
|General Knowledge//p
|Science//s
|what is the speed of light in miles per second?//q
|Choose the best answer from the following//i
|MCQ question//n
|186000//c
|286000//w
|200000//w

【问题讨论】:

  • 所有这三个例子似乎代表了完全不同的数据。您可以添加输入文件的实际示例以及所需的每种不同格式的数据吗?
  • @jkiiski 这些都是我尝试过很多事情的零散示例。对不起。删除它们并在整个过程中添加了一个示例。

标签: parsing lisp common-lisp


【解决方案1】:

对于一个复杂的例子,你有一个简单的问题。这可能只是一个简单的解析问题:你需要的是一个语法和一个解析器。

语法示例。终端项目为大写。 * 表示一个或多个。

s = q
q = Q i*
i = I w*
w = W

简单解析器:

(defun example (sentence)
  (labels ((next-item ()
             (pop sentence))
           (empty? ()
             (null sentence))
           (peek-item ()
             (unless (empty?)
               (first sentence)))
           (expect-item (sym)
             (let ((item (next-item)))
               (if (eq item sym)
                   sym
                 (error "Parser error: next ~a, expected ~a" item sym))))
           (star (sym fn)
             (cons (funcall fn)
                   (loop while (eq (peek-item) sym)
                         collect (funcall fn)))))
    (labels ((s ()
               (q))
             (q ()
               (list (expect-item 'q) (star 'i #'i)))
             (i ()
               (list (expect-item 'i) (star 'w #'w)))
             (w ()
               (expect-item 'w)))
      (s))))

例子:

CL-USER 10 > (example '(q i w w w i w w))
(Q
 ((I (W
      W
      W))
  (I (W
      W))))

【讨论】:

  • 绝妙而神秘的答案。但这并不是那么简单 :-) II 需要定义一个语法,阅读一点编译器理论,查看标记等,最后写了一个递归下降解析的近亲。一旦我掌握了这些,那么改变其他语法变体就很容易了。 lisp 的美妙之处在于我能够修改调用级别(即,代替“I”出现两次,单个 I 带有两个子列表)并且还可以避免显式创建和插入父/子节点函数,递归调用和动态列表构建处理了它。HT 到 Rainer。
猜你喜欢
  • 1970-01-01
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-17
  • 2011-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多