ファイルのセクションを並べ替える


8

大きなファイルで2つの文字列を並べ替えることはできますか?

たとえば、現在のファイルは次のとおりです。

    0cf  Front Brake
    0d0  Rear Brake
    0ce  Handle Bars
HUT 03  VR Controls
    009  Vest
    001  Belt
    002  Body Suit
    020  Stereo Enable
    003  Flexor
    007  Hand Tracker
    004  Glove
    006  Head Mounted Display
    008  Oculometer
    00a  Animatronic Device
    000  Unidentified
    021  Display Enable
    005  Head Tracker
HUT 04  Sport Controls
    000  Unidentified
    002  Golf Club
    001  Baseball Bat

そして、望ましい出力は次のとおりです。

    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

ここでは、セクションHUT 03 VRコントロールHUT 04スポーツコントロールが分類されています。

特定のファイルでは、セクションヘッダーはスペース以外の文字で始まりますが、セクションコンテンツは常にスペースまたはタブで始まります。このファイルには100以上のセクションがあるため、スクリプト/コマンドでセクション名をハードコードすることはできません。


セクションは固定行番号にあるか、パターンによって定義されていますか?
Sparhawk

セクションヘッダーは行の最初の文字として始まりますが、その内容はスペース/タブで始まります。セクションは固定数ではありません。
SHW

(質問とテキストのタイトルごとに)1つのセクションのみ、またはすべてのセクションをソートしますか?
Kusalananda

@Kusalanandaこの点について質問があいまいであることに同意します。ただし、出力例には、ソートされているすべてのセクション(またはその一部)が表示されます。
Stephen Kitt

「HUT」が16進数文字を使用しているとは言えません。
jlliagre

回答:


7

Pythonの場合:

#!/usr/bin/python3

with open("file.txt", "r") as ins:
    lines = []
    for line in ins:
        if line.startswith((" ", "\t")):
            lines.append(line)
        else:
            lines.sort()
            print(*lines, end = "", sep = "")
            print(line, end = "")
            lines = []
    lines.sort()
    print(*lines, end = "", sep = "")

これにより、2つの特定の行の間だけでなく、すべてのセクションが(個別に)ソートされます。


見事!これはマスターストロークです。
SHW

6

おもしろいのは、以下を使用して単一のセクションをソートする方法exです。

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%

6
$ awk 'BEGIN { OFS="\t"; s=0 } /^[^[:blank:]]/ { print ++s "\b", $0; next } { print s, $0 }' file | sort -n | cut -f 2-
    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

これはawk、この行が含まれているセクションに対応する各行の前に番号(およびタブ区切り)を追加するために使用します。セクションヘッダーの場合、番号の後にバックスペース文字を追加します(バックスペースがタブの前にソートされるためです)。次に、これらの数値と追加されたタブ区切り記号を削除する前に、これらの数値で結果のデータを単に並べ替えます。

セクションヘッダーは、行の先頭にある空白以外の文字を探すことによって検出されます。


1
いいね!特にバックスペーストリックが好きです。
Stephen Kitt

1
このアプローチでは、セクション番号(HUTフィールドの後)をプレフィックスとして使用して、セクションを並べ替えることもできます。
Stephen Kitt

3

あなたは得ることができるawksort仕事を得るために協力します。

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • 各コンテンツ行をパイプします sort
  • セクションマーカーが検出さcloseれたsortときに呼び出します。これによりsort、出力が標準出力にフラッシュされて終了します。
  • セクションマーカーを印刷する
  • sortセクションマーカーに続くコンテンツ行の新しいインスタンスが引き継ぎます
  • コールclosesort内容を末尾の世話をするために最後に

1

このようなタスクでは、スクリプトを作成するのが面倒なことがよくあります。一度だけ実行する必要がある場合は、ファイルをいくつか開いて、ファイルを開いて次のように入力すると、マクロを使用して非常に適切に実行できますvim

  • GoFAKE SECTION<ESC>:最後に偽のセクションを追加し、これが行の先頭にあることを確認します(有効にしているcindentautoindent有効になっている場合があります)。これは最後のセクションをソートするためにも必要です。
  • gg:戻るファイルの先頭に移動し、ファイルはセクションで始まり、1行下に移動します j
  • qq:マクロの記録を開始してqを登録
  • v:選択を開始
  • /^\S\+<Enter>:次のセクションの開始を検索
  • k:1行上
  • :!sort<Enter:セクションを並べ替え
  • nj:次のセクションの最初の要素に移動
  • q:マクロの記録を停止
  • @q:マクロを繰り返す
  • 100@@:マクロを数回繰り返します(セクションがなくなるまで)
  • dd:ファイルの最後の行(FAKE SECTION)を削除します

:set lazyredrawマクロの実行を高速化したい場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.