Sha*_*ter 4 lisp parsing text common-lisp
这是一个简短的问题:
输入:一个字符串列表,每个字符串包含数字
("3.4 5.4 1.2 6.4""7.8 5.6 4.3""1.2 3.2 5.4")
输出:一个数字列表
(3.4 5.4 1.2 6.4 7.8 5.6 4.3 1.2 3.2 5.4)
这是我尝试编码:
(defun parse-string-to-float (line &optional (start 0))
"Parses a list of floats out of a given string"
(if (equalp "" line)
nil
(let ((num (multiple-value-list (read-from-string (subseq line start)))))
(if (null (first num))
nil
(cons (first num) (parse-string-to-float (subseq line (+ start (second num)))))))))
(defvar *data* (list " 3.4 5.4 1.2 6.4" "7.8 5.6 4.3" "1.2 3.2 5.4"))
(setf *data* (format nil "~{~a ~}" *data*))
(print (parse-string-to-float *data*))
===> (3.4 5.4 1.2 6.4 7.8 5.6 4.3 1.2 3.2 5.4)
Run Code Online (Sandbox Code Playgroud)
但是,对于相当大的数据集,这是一个缓慢的过程.我猜测递归并不是那么紧,我正在做一些不必要的事情.有任何想法吗?
此外,宏项目涉及获取具有由关键字分隔的各种数据部分的输入文件.示例 -
%FLAG START_COORDS
1 2 5 8 10 12
%FLAG END_COORDS
3 7 3 23 9 26
%FLAG NAMES
ct re ct cg kl ct
Run Code Online (Sandbox Code Playgroud)
等...我正在尝试使用%FLAG后面的关键字作为键解析哈希表,并根据我正在解析的特定关键字将值存储为数字或字符串列表.对于已经完成这类工作的图书馆的任何想法,或者在lisp中解决这个问题的简单方法?
这不是您希望以递归方式开始执行的任务.相反,使用LOOP
和一个COLLECT
子句.例如:
(defun parse-string-to-floats (line)
(loop
:with n := (length line)
:for pos := 0 :then chars
:while (< pos n)
:for (float chars) := (multiple-value-list
(read-from-string line nil nil :start pos))
:collect float))
Run Code Online (Sandbox Code Playgroud)
此外,您可能需要考虑使用WITH-INPUT-FROM-STRING
而不是READ-FROM-STRING
,这使事情更简单.
(defun parse-string-to-float (line)
(with-input-from-string (s line)
(loop
:for num := (read s nil nil)
:while num
:collect num)))
Run Code Online (Sandbox Code Playgroud)
至于性能,您可能想要进行一些分析,并确保您实际上正在编译您的函数.
编辑添加:你需要注意的一件事是,如果你不确定字符串的来源,读者可以引入一个安全漏洞.有一个读取宏,#.
它可以允许在从字符串中读取任意代码时对其进行评估.保护自己的最好方法是将*READ-EVAL*
变量绑定到NIL
,这将使读者在遇到时发出错误信号#.
.或者,您可以使用Rainer Joswig在其答案中提到的专业库之一.
解析单个字符串:
(defun parse-string-to-floats (string)
(let ((*read-eval* nil))
(with-input-from-string (stream string)
(loop for number = (read stream nil nil)
while number collect number))))
Run Code Online (Sandbox Code Playgroud)
处理字符串列表并返回单个列表:
(defun parse-list-of-strings (list)
(mapcan #'parse-string-to-floats list))
Run Code Online (Sandbox Code Playgroud)
示例:
CL-USER 114 > (parse-list-of-strings (list "1.1 2.3 4.5" "1.17 2.6 7.3"))
(1.1 2.3 4.5 1.17 2.6 7.3)
Run Code Online (Sandbox Code Playgroud)
注意:
一个代价高昂的操作是READ从流中读取浮点值.像PARSE-NUMBER这样的库可能更有效 - 一些Common Lisp实现也可能具有READ-FLOAT/PARSE-FLOAT功能.
归档时间: |
|
查看次数: |
4415 次 |
最近记录: |