連続する段落のグループ化されたソート(空白行で区切られています)?


8

私は今、によるソートの経験がかなりあると思います。ただし、これまでのところ、連続する行を並べ替える方法は見つかりませんでした。

次のようなテキストファイルがあるとします:(もちろん非常に簡略化されています)

Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

さて、各ブロックごとにアルファベット順に行をソートすることは可能ですか?つまり、結果は次のようになります。

Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel

sortmanページで見つけたものから言うと、これは組み込みのUNIX sortコマンドでは不可能かもしれません。それとも、外部/サードパーティのツールに頼ることなく実行できますか?

回答:


9

Dravのawkソリューションは優れていますが、それはsort段落ごとに1 つのコマンドを実行することを意味します。それを回避するには、次のようにします。

< file awk -v n=0 '!NF{n++};{print n,$0}' | sort -k1n -k2 | cut -d' ' -f2-

または、次のすべてを行うことができますperl

perl -ne 'if (/\S/){push@l,$_}else{print sort@l if@l;@l=();print}
          END{print sort @l if @l}' < file

上記のセパレータは、空の行ではなく空白行(awk1つは空白文字またはタブ文字のみの行、perl1つは水平または垂直のスペース文字)であることに注意してください。あなたは空行をしたいならば、あなたは置き換えることができ!NF!length$0==""、そして/\S/持ちます/./


特にオーバーヘッドawkを回避するソリューションについて、あなたにも感謝しますsort!卑劣!
構文エラー2013

9
awk -v RS= -v cmd=sort '{print | cmd; close(cmd); print ""}' file

レコードセパレータRSを空の文字列に設定すると、一度に段落のawkステップが実行されます。各段落について、段落を($0)でcmd(これはに設定されていますsort)にパイプし、出力を印刷します。空白行を印刷して、出力段落をで区切りprint ""ます。

perlの例を挙げている場合は、Stephaneのアプローチとは別のアプローチを示します。

perl -e 'undef $/; print join "\n", sort (split /\n/), "\n" 
    foreach(split(/\n\n/, <>))' < file

フィールド区切り記号(undef $/<>を設定解除すると、STDIN全体を使用および取得できます。私たちはsplitそれから\n\n(段落)。foreach「段落」、sortによって行split改行周りティン、sortINGの、その後join一緒に戻ってそれらをINGのと後ろにタック\n

ただし、これには、最後の段落に「末尾の段落」区切り文字が追加されるという副作用があります(前にない場合)。あなたは少しかわいくないでそれを回避することができます:

perl -e 'undef $/; print join "\n", sort (split /\n/) , (\$_ == \$list[-1] ? "" : "\n")
    foreach(@list = split(/\n\n/, <>))' < file

これにより、段落がに割り当てられます@list。次に、それがforeach\$_ == \$list[-1]チェック)の最後の要素であるかどうかをチェックする「3項演算」があります。""? ...)の場合は印刷、それ以外の場合は()他のすべての「段落」(の要素: ...)を印刷"\n"します@list


これはすごいです!ありがとうございました。あなたは実際/usr/bin/sortにその行で呼び出していますか、それともawk組み込みの「ソート」コマンドですか?
syntaxerror

sortコマンドを呼び出すため、各ループでclose(cmd)を実行する必要がある:)
Drav Sloan 2013

5

私は、テキストの段落に対してsort、shuf、tacまたはその他のコマンドを使用できるようにするツールをhaskellで作成しました。

https://gist.github.com/siers/01306a361c22f2de0122
編集:ツールもこのリポジトリに含まれていますhttps : //github.com/siers/haskell-import-sort

テキストをブロックに分割し、\0charを使用してサブブロックを結合し、コマンドをパイプ処理して、最後に同じことを行います。

2015年8月28日:このツールの別の個人的な使用方法を見つけました—行の後にN段落を選択しました。

paramap grep -aA2 '^reddit usernames' < ~/my-username-file
reddit usernames

foo
bar
baz

a couple
more of these

4

GNU awkが利用可能な場合は、組み込みasort()関数を使用して各ブロックをソートできます。このようなもの:

blocksort.awk

function sort_n_print(array) {
  asort(array)
  for(i=1; i<=length(array); i++)
    print array[i]
  delete array
}

NF { a[++x] = $0 }

!NF { sort_n_print(a); print }

END { sort_n_print(a) }

次のように実行します。

awk -f blocksort.awk infile

1

TXR Lispステップバイステップ:

$ cat data
Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

$ txr -p '(get-lines)' < data
("Echo" "Alpha" "Delta" "Charlie" "" "Golf" "Bravo" "Hotel" "Foxtrot")

$ txr -t '(get-lines)' < data
Echo
Alpha
Delta
Charlie

Golf
Bravo
Hotel
Foxtrot

$ txr -p '(partition* (get-lines) (op where [chain length zerop]))' < data
(("Echo" "Alpha" "Delta" "Charlie") ("Golf" "Bravo" "Hotel" "Foxtrot"))

$ txr -p '[mapcar sort (partition* (get-lines) (op where [chain length zerop]))]' < data
(("Alpha" "Charlie" "Delta" "Echo") ("Bravo" "Foxtrot" "Golf" "Hotel"))

$ txr -p '(interpose (list "") [mapcar sort (partition* (get-lines) (op where [chain length zerop]))])' < data
(("Alpha" "Charlie" "Delta" "Echo") ("") ("Bravo" "Foxtrot" "Golf" "Hotel"))

$ txr -t '(interpose (list "") [mapcar sort (partition* (get-lines) (op where [chain length zerop]))])' < data
Alpha
Charlie
Delta
Echo

Bravo
Foxtrot
Golf
Hotel

参考文献:取得ラインパーティション*OP、、チェーン長さzeropでmapcarは挟み込みます


で、外部プロセスを介して文字列をパイプ処理する関数に[mapcar sort ...]置き換えることができることに注意してくださいsort。その後、テキスト処理の外部コマンドを段落に配布するためのツールを作成できます。
Kaz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.