如何从普通 lisp 中的列表列表中获取列表

how to get a list out of list of lists in common lisp

我是普通 lisp 的新手,正在尝试从拆分的字符串中获取列表。 例如: ["4-无 16dia","6-无 20dia"] 现在我只想收集第三个元素,如 ["16","20"] 我已经正确地使用了拆分部分:

(defun my-split (string &key (delimiterp #'delimiterp)
                    )
          (loop :for beg = (position-if-not delimiterp string)
            :then (position-if-not delimiterp string :start (1+ end)
                           )
            :for end = (and beg (position-if delimiterp string :start beg))
            :when beg :collect (subseq string beg end)
              :while end))

其中:

(defun delimiterp (c) (position c " ,-:"))

但只将第三个元素收集到列表中是棘手的部分,我已经尝试过:

(defparameter *list1*
  (loop for i in (cdr list)
     (append (parse-integer
                (nth 0
                     (my-split (nth 3 i)
                               :delimiterp #'delimiterp))))))

P.S:有两个列表 cz 示例字符串本身是列表列表的一部分 请帮助我,提前致谢

我会使用正则表达式,而且我认为我会在很大程度上不考虑我使用的语言。当然,有些语言没有正则表达式,但有了正则表达式就省得重新造轮子了。

在Common Lisp中,正则表达式库叫做Common Lisp - Practical Perl Compatible Regular Expressions,cl-ppcre。我们用 (ql:quickload "cl-ppcre").

加载它

然后可以使用 (ppcre:scan-to-strings "^(\d*)-No (\d*)dia$" x) 对数字进行 return 编辑。正则表达式使用 \d 来挑选一个数字,在 Lisp 字符串中写成 \d。星号表示 return 零个或多个数字。正则表达式中的括号是我们要 return 的位,即数字。

对字符串列表执行此操作只需使用 mapcar.

(defparameter text-match "")
(defparameter text-numbers "")
(defparameter test-text '("4-No 16dia" "6-No 23dia"))


(defun extract-numbers (text)
  (setf (values text-match text-numbers)
    (ppcre:scan-to-strings "^(\d*)-No (\d*)dia$" text))
  text-numbers)

(defun extract-numbers-from-list (lst)
  (mapcar #'extract-numbers lst))

(extract-numbers-from-list test-text) ; => (#("4" "16") #("6" "23"))

编辑:词汇绑定

当我写上面的内容时,我试图让正则表达式正确,同时试图让词法绑定正确。由于时间有限,我努力使正则表达式正确,并使用了动态变量和 setf。好的,它完成了工作,但我们可以做得更好。

经典的词法绑定系统是let,句法(let ( (var1 val1) (var2 val2) ...) body)。我们可以尝试 (let ((x 0))),这是有效的 Lisp 代码,但作用不大。一旦词法作用域结束,变量 x 就被解除绑定。尝试访问 x 会导致错误。

我们可以 return 来自许多函数的多个值,例如 floorscan-to-string。我们现在必须使用 (multiple-value-bind (variable-list) values) 将这些值绑定到变量。大多数网站并没有很好地解释这一点。绑定变量后,我收到有关未绑定变量的错误。好的,值得一提的是 -

multiple-value-bind 词法绑定变量,就像 let.

完整的语法是 (multiple-value-bind (variable-list) values body),您的代码进入正文部分,就像 let 一样。因此上面的代码变成:

(defparameter test-text '("4-No 16dia" "6-No 23dia"))

(defun extract-numbers (text)
   (multiple-value-bind (text-match text-numbers)
     (ppcre:scan-to-strings "^(\d*)-No (\d*)dia$" text)
     text-numbers))

(defun extract-numbers-from-list (lst)
  (mapcar #'extract-numbers lst))

(extract-numbers-from-list test-text) ; => (#("4" "16") #("6" "23"))

没有依赖项,可以使用:

(defun extract-nums (s)
  (mapcar #'(lambda (x) (parse-integer x :junk-allowed t)) 
          (ql-util:split-spaces s)))

并尝试使用:

(defparameter *s*  (list "4-No 16dia" "6-No 20dia"))
(mapcar #'extract-nums *s*)
;; => ((4 16) (6 20))

parse-integer 设置 junk-allowed-p t 有助于从字符串中提取整数。

但是,是的,在现实生活中我也会使用 cl-ppcre,例如 主要是函数 cl-ppcre:splitcl-ppcre:scan-to-strings.

(ql:quickload :cl-ppcre)

(defun extract-nums (s)
  (mapcar #'parse-integer (cl-ppcre:scan-to-strings "(\d+)-No (\d+)dia" s))

从那以后就是

(second (map #'list (mapcar #'extract-nums *s*))
;; => (16 20)

补充一下,cl-ppcre 也有 register-groups-bind 以单一形式进行正则表达式匹配、绑定和转换:

CL-USER> (cl-ppcre:register-groups-bind ((#'parse-integer no dia))
             ("(\d+)-No (\d+)dia" "4-No 16dia")
           (values no dia))
4
16