lisp - строка в структуру или список - PullRequest
1 голос
/ 29 января 2012

У меня проблема с обычным лиспом.

Я хочу передать строку в функцию и хочу, чтобы эти строки стали структурой.Я не могу использовать внешнюю библиотеку.

Например, с этим вводом:

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

Ответы [ 2 ]

3 голосов
/ 30 января 2012

Я бы порекомендовал использовать регулярное выражение для анализа этого. Используя 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))))

Обратите внимание, что вам, вероятно, придется настроить регулярное выражение для лучшего представления фактического формата входной строки, в частности, если какое-либо из полей является необязательным.

2 голосов
/ 29 января 2012

Вам нужно будет проанализировать данные из строки, чтобы вы могли использовать их для своей стойки. Лисп не сделает этого волшебным образом.

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

Обычно я не пишу код для людей, но вот пример парсера, он не самый простой, есть лучшие способы сделать это, но он работает.

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