【问题标题】:lisp - String to struct or listlisp - 结构或列表的字符串
【发布时间】:2012-01-29 17:16:43
【问题描述】:

我对通用 lisp 有疑问。

我想将字符串传递给函数 并希望这个字符串成为一个结构。 我无法使用外部库。

例如这个输入:

(testfu "ftp/http.ok:3345")

这是结构:

(defstruct test-struct
    scheme 
    part
    ans     
port)

我想要这个结果:

方案:“ftp”部分:“http”和“ok”端口“3345”

我该如何做 testfu ?

这是我的错误尝试:(

(defun testfu (x) 
(setq ur1 (make-test-struct :scheme frist x :host second x)))

【问题讨论】:

    标签: list lisp common-lisp


    【解决方案1】:

    我建议使用正则表达式来解析它。使用 Common Lisp 正则表达式库 CL-PPCRE,代码如下所示:

    (defun testfu (x)
      (multiple-value-bind (result values)
          (ppcre:scan-to-strings "^([a-z]+)/([a-z]+)\\.([a-z]+):([0-9]+)$" x)
        (unless result
          (error "String ~s is not valid" x))
        (make-test-struct :scheme (aref values 0)
                          :part (aref values 1)
                          :ans (aref values 2)
                          :port (aref values 3))))
    

    请注意,您可能必须调整正则表达式以更好地表示输入字符串的实际格式,特别是如果任何字段是可选的。

    【讨论】:

    • thnks :) 有没有外部库的方法? :)
    • Common Lisp 规范中没有正则表达式库,如果这是您所要求的。但这不应该阻止您使用它,因为 CL-PPCRE 适用于我所知道的所有 CL 实现。使用 Quicklisp 安装它非常简单。
    【解决方案2】:

    您必须从字符串中解析出数据才能将其用于您的支柱。 Lisp 不会神奇地做到这一点。

    Split Sequence 是一个很好的库

    如果您不想要一个库,那么一些代码可以让您走上正确的轨道。这将基于谓词函数 fn 标记字符串(当字符是分隔符时返回 true,否则返回 false)

    (defun split-by-fn (fn string)
      (let* ((STARTING 0)
             (TOKEN 1)
             (DELIM 2)
             (state STARTING)
             (a-token "")
             (the-list '())
             (str-length (length string)))
        (dotimes (i str-length)
          (if (funcall fn (char string i))
              (progn
                (if (eq state TOKEN)
                    (progn
                      (setq the-list (cons a-token the-list))
                      (setq a-token "")))
                (setq state DELIM))
            (progn
              (setq a-token
                    (concatenate 'string a-token (string (char string i))))
              (setq state TOKEN))))
        (if (eq state TOKEN)
            (setq the-list (cons a-token the-list)))
        (setq the-list (reverse the-list))))
    

    我通常不为人们编写代码,但这里有一个示例解析器,它不是最 lisp-y,有更好的方法来做到这一点,但它确实有效。

    (defun parser ( string )
      (labels ((set-field (state struct token)
                (let ((SCHEME 0)
                      (PART   1)
                      (ANS    2)
                      (PORT   3))
                (cond ((= state SCHEME) 
                        (setf (example-struct-SCHEME struct) token))
                      ((= state PART)  
                        (setf (example-struct-PART struct) token))
                      ((= state ANS)  
                        (setf (example-struct-ANS struct) token))
                      ((= state PORT)  
                        (setf (example-struct-PORT struct) token))))))
        (let ((state  0)
              (token "")
              (check 0)
              (a-list '())
              (struct (make-example-struct)))
          (loop for char across string do
            (progn
              (setq check (position char "/.:"))
              (if check
                (progn
                  (set-field state struct token)
                  (setq token "")
                  (setq state (+ check 1)))
                (setq token (concatenate 'string token (string char))))))
          (progn
            (if (/= 0 (length token))
              (set-field state struct token))
              struct))))
    

    【讨论】:

    • thnks :) 但如果不想按顺序?例如:val port 是字符“:”后面的值我可以扫描字符串吗? :)
    • 你可以构建一个解析器,如果在 fn 上进行标记,它会运行一个 cond 块,它根据 char 的值执行操作。
    • 感谢代码,但我可以在我的函数中实现?我不明白如何使用它:(
    • 一个例子? :(请帮助我@Mimisbrunnr
    猜你喜欢
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多