2

次の形式のsedを使用して、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
4

3 に答える 3

3

私はスキームについて何も知らないので、おそらくsedではなくawkでこれを行うでしょう。

[ghoti@pc ~]$ cat data.txt 
1,{},344.233
1,{2},344.197
2,{16},290.281
2,{18},289.093
3,{1},220.896
[ghoti@pc ~]$ 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));
}

[ghoti@pc ~]$ ./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)))
[ghoti@pc ~]$ 

それは確かにもっときつく書くことができます、しかしこれは仕事を成し遂げます。

更新:(コメントごと)

[ghoti@pc ~]$ tail -1 data.txt 
3,{1,3,4},220.896
[ghoti@pc ~]$ 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);
 }

[ghoti@pc ~]$ ./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)))
[ghoti@pc ~]$ 

何が起きてる?

追加する新しいブロックで、2番目のフィールドがで終わるかどうかをテストします}。そうでない場合は、ループするまでループします。ループを実行するたびに、の前のコンマを削除}して、スペースに置き換えます。

時々、ブルートフォースが機能します。:-P

于 2012-05-30T03:32:21.813 に答える
3

ラケット(別名スキーム):

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

これをrewrite.rktとして保存し、次のように実行します。

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}行を追加したことに注意してください。

また、出力では'(...)ではなく(quote ...)が使用されていることに注意してください。これは「正常に機能するはずです」。つまり、Schemeリーダーは、これら2つの形式に対して同じ出力を生成し、結果のファイルはスキーム入力として正常に機能するはずです。

これが私のコードである場合、(v1を定義する...)ダンスは行わず、スキーム/ラケットプログラムが1回の「読み取り」で丸呑みできる大きなデータとして書き出すだけだと思います。 、しかしそれはあなたの選択であり、私のものではありません。また、仕様にはいくつかのあいまいさがあります。初期インデックスの一意性。つまり、以前の行番号に「戻る」ことができます。たとえば、この入力ファイルが与えられたときの出力は次のようになります。

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

また、短く/きれいに見えるようにするために、すべてのテストケースを切り取ったことにも注意してください:)。

編集:ああ!代わりに、この方法で行を収集します。実際には少し遅くなりますが、読みやすくなります。

#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)))))))
于 2012-05-30T05:22:03.660 に答える
0

これはあなたのために働くかもしれません(GNU sed):

 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

説明:

  • 同様の値を1行に減らします:a;$!N;s/^\(\([^,])*\).*\)\n\2/\1/;ta
  • パターンスペース(PS)をコピーしてスペース(HS)を保持します。h
  • HSにスワップx
  • 前の行を切り落とします。s/\n.*//
  • リストを作成します。s/,{\([^}]*\)},\([^,]\+\)/ ((\1) \2)/g
  • 残り,のをスペースに置き換えます。s/,/ /g
  • リストを関数定義とコメントで囲み、印刷します。s/^\([^ ]*\).*/(define v\1 '\''(&)) ;;...\1/p
  • PSにスワップバックします。x
  • 前の行まで削除して繰り返します。D
于 2012-05-30T10:45:46.893 に答える