2016-07-10 1 views
2

2 차원 배열을 표준 입력에서 Common Lisp (SBCL)의 데이터 구조로 파싱하려고합니다. I 입력 폼Common Lisp 입력에서 2 차원 배열을 파싱

1 2 3 
4 5 6 
7 8 9 

은 3 개 행이 있는지 될 것으로 예상된다.

지금까지 나는이 왔 :

(defun read-2d-array (rows &rest args) 
    (values (read-from-string 
      (concatenate 'string "#2A(" 
          (dotimes (i rows) 
          (concatenate 'string "(" 
             (apply #'read-line args) 
             ")")) 
          ")")))) 

이의 문제는 외부 CONCATENATE가 작동하는 것 같다 동안, 나는 루프 반복을 통해 연결하여 양식을 얻으려고 노력하는 데 문제가 있다는 것입니다 :

#2A((1 2 3)(4 5 6)(7 8 9)) 

도움이 되겠습니다. 감사!

답변

1

이 모든 접합하는 가장 좋은 방법이 아니다.

Common Lisp는 문자열을 사용하여 읽고 인쇄 할 수 있습니다.

그냥 WITH-OUTPUT-TO-STRING에 의해 만들어진 문자열 출력 스트림에 인쇄 :

(defun convert-text-to-array-string (stream) 
    (with-output-to-string (out-stream) 
    (write-string "#2A(" out-stream) 
    (loop for line = (read-line stream nil nil) 
      while line 
      do 
      (write-string "(" out-stream) 
      (write-string line out-stream) 
      (write-string ")" out-stream)) 
    (write-string ")" out-stream))) 

WITH-OUTPUT-TO-STRING에서 반환 형식은 스트림에 다 출력의 결과 문자열을 반환합니다.

0

dotimes 양식은 nil을 반환합니다.

당신은 당신이 읽은 선을 연결해야합니다

(defun read-2d-array (rows &rest args) 
    (values (read-from-string 
      (concatenate 'string "#2A(" 
         (apply #'concatenate 'string 
           (loop :repeat rows 
           :collect (apply #'read-line args))) 
         ")")))) 
2

오히려 문자열을하고 밖으로 문자 배열을 읽기보다는 자신을 PARSE-INTEGER으로 invidual 번호를 분석하고 배열로 넣어 더 좋을 것이다 그것의.

(defun read-2d-array (rows &rest args) 
    ;; I'm assuming that the array is a square matrix. Otherwise you'd 
    ;; need the number of columns too. 
    (let ((arr (make-array (list rows rows) 
         :element-type 'integer 
         :initial-element 0))) 
    (dotimes (i rows) 
     (let ((line (apply #'read-line args)) 
      (start 0)) 
     (dotimes (j rows) 
      (multiple-value-bind (number end) 
       (parse-integer line :start start 
            :junk-allowed t) 
      (setf start end 
        (aref arr i j) number))))) 
    arr)) 

(with-input-from-string (str "1 2 3 
4 50 6 
7 8 9") 
    (read-2d-array 3 str)) 
;=> #2A((1 2 3) (4 50 6) (7 8 9)) 

편집 그냥 안전을 위해 여기 입력의 첫 번째 줄을보고 열 수를 파악 버전입니다.

(defun read-2d-array (rows &rest args) 
    (let* ((first-line (apply #'read-line args)) 
     (cols (1+ (count #\space first-line))) 
     (arr (make-array (list rows cols) 
          :element-type 'integer 
          :initial-element 0))) 
    (loop for i below rows 
      for line = first-line then (apply #'read-line args) 
      for start = 0 
      do (dotimes (j cols) 
       (multiple-value-bind (number end) 
        (parse-integer line :start start 
             :junk-allowed t) 
       (setf start end 
         (aref arr i j) number)))) 
    arr)) 

또는 라인의 정수를 추출 CL-PPCRE를 사용하여 :

(defun read-2d-array (rows &rest args) 
    (labels ((numbers (string) 
      (mapcar #'parse-integer 
        (cl-ppcre:all-matches-as-strings "\\d+" string)))) 
    (let* ((first-line (numbers (apply #'read-line args))) 
      (cols (length first-line)) 
      (arr (make-array (list rows cols) 
          :element-type 'integer 
          :initial-element 0))) 
     (loop for i below rows 
      for line = first-line then (numbers (apply #'read-line args)) 
      do (dotimes (j cols) 
       (setf (aref arr i j) (pop line)))) 
     arr))) 
+0

미리 행과 열의 수를 알면 그 질문에 함축되어 있다고 생각하지 않습니까? – BRFennPocock

+0

@BRPocock 질문의 함수는'rows'를 인자로가집니다. 예제 입력이 정사각형 이었기 때문에 숫자 열이 같거나 (적어도 알 수 있다고 가정하는 것이 안전 할 것이라고 생각했습니다. – jkiiski

+0

OP가 일반 "CSV"리더와 같은 것을 찾고있을 수도 있지만 질문에 명확하게 지정되지 않았을 것이라고 추측합니다. – BRFennPocock