2012-01-29 116 views
1

我有一個常見的lisp問題。lisp - 字符串結構或列表

我想將一個字符串傳遞給函數 ,並希望這些字符串變成一個結構體。 我無法使用外部庫。

例如與該輸入:

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

這是結構:

(defstruct test-struct 
    scheme 
    part 
    ans  
port) 

我想這樣的結果:

方案: 「FTP」 部分: 「HTTP」 「ok」port「3345」

我該怎麼做testfu?

這裏是我不好試試:(

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

回答

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)))) 

我通常不會寫代碼的人,但這裏有一個例子分析器,它不是最口齒不清-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)))) 
+0

thnks :)但如果不想按順序? 例如: val port是charather後面的值:「」 我可以掃描字符串嗎? :) – r1si 2012-01-29 18:01:49

+0

你可以建立一個解析器,相反,如果fn上的標記化運行一個cond塊,它會根據char的值來執行某些操作。 – zellio 2012-01-29 18:23:26

+0

thnks的代碼,但我可以在我的功能實現? 我不明白我怎麼可以用它:( – r1si 2012-01-30 12:41:05

3

我建議使用正則表達式來解析這個。使用CL-PPCRE這是Common Lisp的正則表達式庫,代碼應該是這樣的:

(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)))) 

請注意,你可能需要調整正則表達式來更好地代表輸入字符串的實際格式,特別是如果任何字段都是可選的。

+0

thnks :) 有沒有外部libary方式?:) – r1si 2012-01-30 11:55:04

+0

沒有正則表達式庫作爲Common Lisp的規範的一部分如果這就是你要求的。這不應該阻止你使用它,因爲CL-PPCRE適用於我所知道的所有CL實現。使用Quicklisp進行安裝非常簡單。 – 2012-02-01 01:57:19