2012-01-29 8 views
1

共通のlispに問題があります。lisp - 構造体またはリストへの文字列

文字列を関数 に渡し、この文字列を構造体にしたいと考えています。 外部ライブラリは使用できません。この入力で例えば

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

これは構造体である:

(defstruct test-struct 
    scheme 
    part 
    ans  
port) 

私はこの結果をしたい:

スキーム: "FTP" の部分: "HTTP" an "ok" port "3345"

testfuはどのようにすればいいですか?ここ

私の悪い試し:(

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

答えて

2

あなたは、あなたのストラットのためにそれを使用するかもしれないようにするために、文字列からのデータを解析する必要があります。Lispは魔法のことを行うことはありません。

Split Sequenceはそのための良いライブラリです

ライブラリを必要としない場合は、正しいトラックにあなたを得るためのコードがあります。これは、述語関数fnに基づいて文字列をトークン化します区切り文字で、そうでない場合は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)))) 
+0

thnks :)しかし、いけないのか? 例: valポートは次の値です: " 文字列をスキャンできますか? :) – r1si

+0

あなたはパーサーを構築することができます。その代わりに、fnでトークン化すると、charの値に基づいて処理するcondブロックが実行されます。 – zellio

+0

コードのthnksが私の機能で実装することはできますか? 私はそれをどのように使用することができないのですか?( – r1si

3

これを解析するために正規表現を使用することをおすすめします。 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)))) 

注、特に場合いずれのフィールドもオプションです。

+0

thnks :) 外部ライブラリなしの方法がありますか?:) – r1si

+0

Common Lisp仕様の一部として正規表現ライブラリがありませんそれがあなたが求めているものなら。 CL-PPCREは、私が知っているすべてのCL実装で動作するので、あなたがそれを使用するのを止めるべきではありません。 Quicklispでインストールするのはとても簡単です。 –

関連する問題