Common Lisp将类似Regex的模式应用于PLIST中的键

时间:2018-03-08 17:29:31

标签: regex lisp common-lisp plist

我想知道是否可以将类似Regex的模式匹配应用于plist中的键。

也就是说,假设我们有一个像(:input1 1 :input2 2 :input3 3 :output1 10 :output2 20 ... :expand "string here")

这样的列表

我需要编写的代码类似于:

“如果列表的键中有:expand和(:input*:output*),那么请执行操作并返回:expand和(:output*:input*)“。

显然,这可以通过cond完成,但我没有看到一个明确的方式来优雅地写这个。因此,我想到可能在键上使用类似Regex的模式,并根据模式搜索的结果返回。

任何建议都表示赞赏。

1 个答案:

答案 0 :(得分:4)

规范化您的输入

算法的第一步可以简化问题的其余部分,即以一种以结构化方式保留相同信息的方式规范化输入,而不是在符号内部。我正在将符号转换为符号或列表。您还可以定义自己的类,它表示输入和输出,并编写适用于两者的通用函数。

(defun normalize-key (key)
  (or (cl-ppcre:register-groups-bind (symbol number)
          ("^(\\w+)(\\d+)$" (symbol-name key))
        (list (intern symbol "KEYWORD")
              (parse-integer number)))
      key))

(defun test-normalize ()
  (assert (eq (normalize-key :expand) :expand))
  (assert (equal (normalize-key :input1) '(:input 1))))

以上normalize-key:inputN解构为(:input N)列表,N解析为数字。使用上面的函数,您可以规范化整个列表(如果需要,您也可以递归地对值进行操作):

(defun normalize-plist (plist)
  (loop
    for (key value) on plist by #'cddr
    collect (normalize-key key)
    collect value))

(normalize-plist
 '(:input1 1 :input2 2 :input3 3 :output1 10 :output2 20 :expand "string here"))

=> ((:INPUT 1) 1
    (:INPUT 2) 2
    (:INPUT 3) 3
    (:OUTPUT 1) 10
    (:OUTPUT 2) 20
    :EXPAND "string here")

从那里,您应该能够更轻松地实现您的逻辑。