sedを使用したテキスト操作


12

現在、次のような内容のテキストファイル(複数行)が複数あります。

565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

各行を次の形式に変更したいと思います。

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

sedを使用して上記を行う方法はありますか?または、Pythonに頼る必要がありますか?

回答:


22

はい、sedでできますが、他のツールの方が簡単です。例えば:

$ awk '{
        printf "%s ", $2; 
        for(i=3;i<=NF;i++){
            printf "%s:%s:1 ",$1,$(i) 
        }
        print ""
       }' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

説明

awkは各フィールドを保存し、(デフォルトでは)空白の入力のそれぞれの行を分割します$1$2$N。そう:

  • printf "%s ", $2; 2番目のフィールドと末尾のスペースを出力します。
  • for(i=3;i<=NF;i++){ printf "%s:%s:1 ",$1,$(i) }:フィールド3から最後のフィールド(フィールドNFの数)まで反復し、それぞれのフィールドに対して、最初のフィールド、a :、次に現在のフィールドおよびaを出力します:1ます。
  • print "" :これは、最後の改行を出力するだけです。

またはPerl:

$ perl -ane 'print "$F[1] "; print "$F[0]:$_:1 " for @F[2..$#F]; print "\n"' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

説明

-a作るには、perlのように振る舞うawkと空白にその入力を分割します。ここで、フィールドは配列@Fに格納されます。つまり、1番目のフィールドは$F[0]2番目、2番目$F[1]などになります。

  • print "$F[1] " :2番目のフィールドを印刷します。
  • print "$F[0]:$_:1 " for @F[2..$#F];:フィールド3から最後のフィールドまで反復し($#F配列内の要素の数である@Fため@F[2..$#F]、3番目の要素から配列の最後まで配列スライスを取ります)、1番目のフィールド、a :、現在のフィールド、aを出力します:1
  • print "\n" :これは、最後の改行を出力するだけです。

12

がここにあります 恐ろしい sed 仕方!

$ sed -r 's/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/; :a s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /; t a; s/ $//' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

より読みやすい:

sed -r '
s/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/
:a 
s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /
t a
s/ $//'

ノート

  • -r EREを使用する
  • s/old/new/置き換えるoldnew
  • ^([0-9]+) 行の先頭にいくつかの番号を保存します
  • \1 最初に保存されたパターンへの後方参照
  • :a スクリプトのこのセクションにラベルを付ける a
  • ( |$) スペースまたは行末
  • t 最後の交換が成功したかどうかをテストします-成功した場合は、次のコマンドを実行します
  • aラベル:aを見つけて、もう一度やり直してください
  • s/ $// 末尾のスペースを削除します

したがって、構造を最初の部分に追加した後、構造の最後のインスタンスを繰り返し見つけて、次の番号に適用します...

しかし、私は他のツールがそれを簡単にすることに同意します...


私はあなたのsedソリューションを待っていました:D
Ravexina

: -私はmuruは、クリーナーのものを作ることができます数えるDは、それは私にしばらくかかった@Ravexina
Zanna

5

awkの場合:

awk '{printf "%s ",$2; for (i=3; i<=NF; i++) printf $1":"$i":1 "; printf "\n"}' file

またはbashを使用:

while read -r -a a; do                  # read line to array a
  printf "%s " ${a[1]}                  # print column #1
  for ((i=2;i<${#a[@]};i++)); do        # loop from column #2 to number of columns
    printf "%s " "${a[0]}:${a[$i]}:1"   # print content/values
  done
  echo                                  # print line break
done < file                             # read file from stdin

出力:

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

5

まあ、あなたはsedでそれを行うことができますが、Pythonも動作します。

$ ./reformatfile.py  input.txt                                                                        
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

内容は次のreformatfile.pyとおりです。

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as fd:
    for line in fd:
        words = line.strip().split()
        pref = words[0]
        print(words[1],end=" ")
        new_words = [ ":".join([pref,i,"1"]) for i in words[2:] ]
        print(" ".join(new_words))

これはどのように作動しますか?特に特別なことは何もありません。最初のコマンドライン引数を読み取り用のファイルとして開き、各行を「単語」または個々のアイテムに分解します。最初の単語はpref可変になり、スペースで終わる標準出力の2番目(words [1])アイテムに出力します。次に、リスト内包表記を介して「単語」の新しいセットを.join()作成し、pref、各単語、およびstringの一時リストで機能します"1"。最後のステップはそれらを印刷することです


4

awk

awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i);\
          printf("%s:%s:1\n", $1, $NF)}' file.txt

スペースで区切られたフィールドを目的の形式にフォーマットすることがすべてです。

  • printf("%s ", $2) 2番目のフィールドに末尾スペースを出力します

  • for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i) 最後から3番目から2番目のフィールドを反復処理し、目的の形式(最初のフィールド、次にコロン、次に現在のフィールド、次にコロン、最後に1)でフィールドを出力します。

  • printf("%s:%s:1\n", $1, $NF) 最後のフィールドに改行を出力します

例:

% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

% awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i); printf("%s:%s:1\n", $1, $NF)}' file.txt
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.