2012-05-30 1 views
2

내가 사용 계획 목록에 data.txt로 변환하고자하는 다음과 같은 형식으로 나오지 :계획 목록에 파일 내용을 변환 나오지 사용

같은 시작 번호가 모든 라인이 구문 분석과 같이 결합됩니다 - 각 :

data.txt로

1,{},344.233 
1,{2},344.197 
2,{16},290.281 
2,{18},289.093 
3,{1},220.896 

foo.scm

(define v1 '(1 (() 344.233) ((2) 344.197))) ;; this is for first two lines starting with 1 
(define v2 '(2 ((16) 290.281) ((18) 289.093))) ;; ... 2 
(define v3 '(3 (() 237.558))) ;; ... 3 
+0

[무엇을 시도해 봤습니까?] (http://mattgemmell.com/2008/12/08/what-have-you-tried/)? – ghoti

+0

@ghoti : 나는 bash와 scheme을 사용하여 직접 파싱을 시도했지만 두 가지 모두에 익숙하지 않다. 아마 완전한 해결책이 필요 없지만 내가 시작할 수있는 것은 괜찮을 것이다. – Mark

+1

왜 그것을 체계로 파싱하지 않습니까? –

답변

3

나는 noth을 알고 ing 계획에 대해, 그래서 아마 sed보다는 awk에서 이것을 할 것입니다.

[[email protected] ~]$ cat data.txt 
1,{},344.233 
1,{2},344.197 
2,{16},290.281 
2,{18},289.093 
3,{1},220.896 
[[email protected] ~]$ cat doit.awk 
#!/usr/bin/awk -f 

BEGIN { 
    FS=","; 
    last1=1; 
} 

$1 != last1 { 
    printf("(define v%.0f '(%.0f %s))\n", last1, last1, substr(sect,2)); 
    last1=$1; sect=""; 
} 

{ 
    gsub(/[^0-9]/,"",$2); 
    sect=sprintf("%s ((%s) %s)", sect, $2, $3); 
} 

END { 
    printf("(define v%.0f '(%.0f %s))\n", last1, last1, substr(sect,2)); 
} 

[[email protected] ~]$ ./doit.awk data.txt 
(define v1 '(1 (() 344.233) ((2) 344.197))) 
(define v2 '(2 ((16) 290.281) ((18) 289.093))) 
(define v3 '(3 ((1) 220.896))) 
[[email protected] ~]$ 

확실히 더 자세히 작성할 수는 있지만 작업이 완료됩니다.

UPDATE : (코멘트를)

[[email protected] ~]$ tail -1 data.txt 
3,{1,3,4},220.896 
[[email protected] ~]$ diff -u doit.awk doitnew.awk 
--- doit.awk 2012-05-30 00:38:34.549680376 -0400 
+++ doitnew.awk 2012-05-30 00:38:52.893810815 -0400 
@@ -10,8 +10,15 @@ 
    last1=$1; sect=""; 
} 

+$2 !~ /}$/ { 
+ while ($2 !~ /}$/) { 
+ pos=match($0, /,[0-9,]+}/); 
+ $0=substr($0, 0, pos-1) " " substr($0, pos+1); 
+ } 
+} 
+ 
{ 
- gsub(/[^0-9]/,"",$2); 
+ gsub(/[^0-9 ]/,"",$2); 
    sect=sprintf("%s ((%s) %s)", sect, $2, $3); 
} 

[[email protected] ~]$ ./doitnew.awk data.txt 
(define v1 '(1 (() 344.233) ((2) 344.197))) 
(define v2 '(2 ((16) 290.281) ((18) 289.093))) 
(define v3 '(3 ((1 3 4) 220.896))) 
[[email protected] ~]$ 

여기 무슨 일이야?

추가 할 새 블록에서 두 번째 필드가 }으로 끝나는 지 테스트합니다. 그렇지 않은 경우 루프가 실행됩니다. 루프가 실행될 때마다 } 앞에 쉼표가 제거되고 공백으로 바뀝니다.

때로는 무차별 대항력이 작용합니다. rewrite.rkt로

#lang racket 

;; parse a line (we will join them later) 
(define (line-parse l) 
    (match (regexp-match #px"([0-9]+),\\{([0-9,]*)\\},([0-9.]+)" l) 
    [(list dc first-num bracket-nums rest) 
    (list (string->number first-num) 
      (match bracket-nums 
      ["" empty] 
      [else (map string->number 
         (regexp-split #px"," bracket-nums))]) 
      (string->number rest))] 
    [else 
    (error "unexpected line format in line: ~s\n" l)])) 

;; join together lines that start with the same number 
(define (join-lines lines) 
    (cond [(empty? lines) empty] 
     [else (join-lines-of-n (first (first lines)) 
           lines 
           empty)])) 

;; gather together lines starting with 'n': 
(define (join-lines-of-n n lines accum) 
    (cond [(empty? lines) 
     (list (cons n (reverse accum)))] 
     [(equal? (first (first lines)) n) 
     (join-lines-of-n n (rest lines) (cons (rest (first lines)) 
               accum))] 
     [else 
     (cons (cons n (reverse accum)) 
       (join-lines lines))])) 

(define (dress-up line) 
    (format "~a\n" `(define ,(format "v~s" (first line)) 
        ',line))) 


(display 
(apply 
    string-append 
    (map dress-up 
     (join-lines 
     (map line-parse 
      (sequence->list (in-port read-line))))))) 

저장이, 다음과 같이 실행 : 라켓 (일명 계획)에서 P는

+0

작은 문제가 있습니다. 중괄호에 '3, {1,3,4}, 220.896'과 같은 하나 이상의 항목이있는 행이 있습니다. 코드를 수정하면 어떻게됩니까? – Mark

+0

그 상황을 어떻게 처리 하시겠습니까? '(v3 '(1,3,4 ((1) 220.896)))'? – ghoti

+0

그래서 그것은 같을 것이다. (v3 '((1 3 4) 220.896))) – Mark

3

oiseau:/tmp clements> racket ./rewrite.rkt < foo.txt 
(define v1 (quote (1 (() 344.233) ((2) 344.197)))) 
(define v2 (quote (2 ((16) 290.281) ((18) 289.093)))) 
(define v3 (quote (3 ((1) 220.896) ((4 5) 2387.278)))) 

을 ...주의가 나는 {4를 추가 한 , 5} 줄을 입력 예제에 추가합니다.

또한 출력에 '(...) 대신 (인용 ...)을 사용합니다. 이 "잘 작동합니다"; 즉, Scheme 판독기는이 두 형식에 대해 동일한 출력을 생성하며 결과 파일은 체계 입력으로 올바르게 작동해야합니다.

이것이 내 코드라면, 나는 (v1을 정의 ...) 댄스를하지 않을 것이라고 생각하고, 스킴/라켓 프로그램이 독신 "읽기",하지만 그것은 내가 선택한 것이 아닙니다. 또한, 귀하의 사양에 약간의 모호성이 있습니다 : 초기 색인의 고유성; 즉, 이전 줄 번호로 "돌아갈"수 있습니다. 예를 들어,이 입력 파일이 주어진 경우 출력은 무엇이되어야합니까?

3,{1},1.0 
4,{1},1.0 
3,{1},1.0 

?

또한 모든 테스트 사례를 더 짧게/더 예쁘게 만들기 위해 모든 테스트 사례를 다듬 었습니다.

EDIT : OH! 대신이 방법으로 줄을 모으십시오.(GNU가 나오지도)이 당신을 위해 작동 할 수

#lang racket 

;; parse a line (we will join them later) 
(define (line-parse l) 
    (match (regexp-match #px"([0-9]+),\\{([0-9,]*)\\},([0-9.]+)" l) 
    [(list dc first-num bracket-nums rest) 
    (list (string->number first-num) 
      (match bracket-nums 
      ["" empty] 
      [else (map string->number 
         (regexp-split #px"," bracket-nums))]) 
      (string->number rest))] 
    [else 
    (error "unexpected line format in line: ~s\n" l)])) 

;; does the line start with the number k? 
(define ((starts-with k) l) (equal? (first l) k)) 

;; join together lines starting with the same thing: 
(define (join-lines lines) 
    (for/list ([k (remove-duplicates (map first lines))]) 
    (cons k (map rest (filter (starts-with k) lines))))) 

(define (dress-up line) 
    (format "~a\n" `(define ,(format "v~s" (first line)) 
        ',line))) 


(display 
(apply 
    string-append 
    (map dress-up 
     (join-lines 
     (map line-parse 
      (sequence->list (in-port read-line))))))) 
0

: 사실은 조금 느려질 수 있습니다,하지만 훨씬 더 잘 읽고

sed ':a;$!N;s/^\(\([^,])*\).*\)\n\2/\1/;ta;h;x;s/\n.*//;s/,{\([^}]*\)},\([^,]\+\)/ ((\1) \2)/g;s/,/ /g;s/^\([^ ]*\).*/(define v\1 '\''(&)) ;;...\1/p;x;D' file 

설명 :

  • 같은 감소 값을 한 줄로 입력 :a;$!N;s/^\(\([^,])*\).*\)\n\2/\1/;ta
  • 공백을 유지하기위한 패턴 복사 공간 (HS). h
  • HS로 전환 x
  • 이전 줄을 잘라내십시오. s/\n.*//
  • 목록을 구성하십시오. s/,{\([^}]*\)},\([^,]\+\)/ ((\1) \2)/g
  • 나머지 ,을 공백으로 대체하십시오. s/,/ /g
  • 기능 정의 및 주석 및 인쇄 기능이있는 서라운드 목록. s/^\([^ ]*\).*/(define v\1 '\''(&)) ;;...\1/p
  • PS로 다시 전환하십시오. x
  • 이전 줄까지 삭제하고 반복하십시오. D
+0

... NO CARRIER ;-) – ghoti