2

私は巨大なファイル、本当に巨大なファイル(約600MB以上のテキスト)を持っています。実際、彼らはjsonsです。それぞれjsonが新しいラインにあり、いくつかのフレーバーしかありません。

彼らは次のように見えます:

{"text":{"some nested words":"Some more","something else":"Yeah more stuff","some list":["itemA","ItemB","itemEtc"]},"One last object":{"a thing":"and it's value"}}

そして、私が欲しいのは、sedを実行し、テキストを吸い出し、次のペアごとにインデントを入れることです。

{
 -{
--[]
 -}
--{}
 -}
}

(出力でネストが正しく行われたかどうかは100%わかりませんが、正しいと思います)

これは可能ですか?私はこれを見て、それが想像できる最も近いものでしたが、それは括弧2を取り除きます。

そこでの答えはブラッシングを使用していることに気付いたので、それが必要だと思います。ある種のs/pattern/newline+tab/space/gタイプコマンドを実行する必要がありますが、それをどのように、何を行うのかわかりません...

誰か助けてもらえますか?純粋である必要はありませんsedが、それが好まれます。

4

4 に答える 4

5

これはきれいではありません...=)これがsedスクリプトとしての私の解決策です。最初の行で、スクリプトを実行するためにsedを呼び出す方法をシェルに通知する必要があることに注意してください。ご覧のとおり、「-n」フラグが使用されているため、sedは、「p」または「P」コマンドを使用して明示的にコマンドした内容のみを出力するように強制します。「-f」オプションは、オプションに続く名前でファイルからコマンドを読み取るようにsedに指示します。スクリプトのファイル名はシェルによって最終コマンドに連結されるため、スクリプトからコマンドが適切に読み取られます(つまり、「。/ myscript.sed」を実行すると、シェルは「/ bin / sed-nfmyscript」を実行します。 .sed ")。

#!/bin/sed -nf

s/[^][{}]//g

t loop
: loop

t dummy
: dummy

s/^\s*[[{]/&/
t open

s/^\s*[]}]/&\
/
t close
d

: open
s/^\(\s*\)[[]\s*[]]/\1[]\
/
s/^\(\s*\)[{]\s*[}]/\1{}\
/

t will_loop
b only_open

: will_loop
P
s/.*\n//
b loop

: only_open

s/^\s*[[{]/&\
/
P
s/.*\n//
s/[][{}]/ &/g
b loop

: close
s/ \([][{}]\)/\1/g
P
s/.*\n//
b loop

始める前に、まずすべてを角かっこと角かっこに分割する必要があります。それが最初の「s」コマンドの責任です。sedに、角かっこでも角かっこでもないすべての文字を何も置き換えないように指示します。それを除く。一致する角かっこは一致する文字のグループを表しますが、その中の最初の文字が「^」の場合、実際には「^」の後に指定された文字を除くすべての文字と一致します。閉じ角かっこを一致させたいので、無視する文字のグループを角かっこで閉じる必要があるため、「^」に続く最初の文字にすることで、閉じ角かっこをグループに含める必要があることを示します。次に、残りの文字を指定できます。角かっこを開く、角かっこを開き、角かっこを閉じます(無視される文字のグループ: "] [{}")。次に、角かっこを閉じてグループを閉じます。これは混乱を招く可能性があるため、ここでさらに詳しく説明しようとしました。

次に、実際のロジックについて説明します。アルゴリズムは非常に単純です。

while line isn't empty
    if line starts with optional spaces followed by [ or {
        if after the [ or { there are optional spaces followed by a respective ] or }
            print the respective pair, with only the indentation spaces, followed by a newline
        else
            print the opening square or normal bracket, followed by a newline
            remove what was printed from the pattern space (a.k.a. the buffer)
            add a space before every open or close bracket (normal or square)
        end-if
    else
        remove a space before every open or close bracket (normal or square)
        print the closing square or normal bracket, followed by a newline
        remove what was printed from the pattern space
    end-if
end-while

しかし、いくつかの癖があります。まず第一に、sedは「while」ループまたは「if」ステートメントを直接サポートしていません。最も近いのは「b」コマンドと「t」コマンドです。「b」コマンドは、C gotoステートメントと同様に、事前定義されたラベルに分岐(ジャンプ)します。「t」も事前定義されたラベルに分岐しますが、現在の行で実行されているスクリプトの開始以降、または最後の「t」コマンド以降に置換が発生した場合に限ります。ラベルは「:」コマンドで書き込まれます。

最初のコマンドが実際に少なくとも1つの置換を実行する可能性が非常に高いため、それに続く最初の「t」コマンドによって分岐が発生します。他のいくつかの置換をテストする必要があるため、次の「t」コマンドが最初のコマンドのために自動的に成功しないことを確認する必要があります。そのため、そのすぐ上の行に「t」コマンドを指定して開始します(つまり、分岐するかどうかに関係なく、同じポイントで続行します)。したがって、「t」で使用される内部フラグを「リセット」できます。コマンド。

「ループ」ラベルは少なくとも1つの「b」コマンドから分岐するため、「t」コマンドのみがクリアできるため、「b」の実行時に同じフラグが設定される可能性があります。したがって、今回は「ダミー」ラベルを使用して、フラグをリセットするために同じ回避策を実行する必要があります。

ここで、開いた角かっこまたは開いた閉じかっこが存在するかどうかを確認して、アルゴリズムを開始します。それらの存在をテストするだけなので、一致をそれ自体に置き換える必要があります。これは「&」が表すものであり、一致が成功すると、sedは「t」コマンドの内部フラグを自動的に設定します。一致が成功した場合は、「t」コマンドを使用して「open」ラベルに分岐します。

それが成功しない場合は、近い正方形に一致するか、ブラケットに通常一致するかを確認する必要があります。コマンドはほぼ同じですが、閉じ括弧の後に改行を追加します。これを行うには、一致を配置した場所の後に(つまり、「&」の後に)、エスケープされた改行(つまり、バックスラッシュの後に実際の改行が続く)を追加します。上記と同様に、一致が成功した場合は、「t」コマンドを使用して「close」ラベルに分岐します。成功しなかった場合は、その行を無効と見なし、パターンスペース(バッファ)をすぐに空にして、次の行でスクリプトを再開します。すべて1つの「d」コマンドを使用します。

「オープン」ラベルを入力して、最初に、一致するオープンブラケットとクローズブラケットのペアの場合を処理します。それらが一致する場合は、それらの前にスペースを入れずに、改行で終わるインデントスペースを付けて印刷します。ブラケットペアのタイプ(正方形または通常)ごとに1つの特定のコマンドがありますが、それらは類似しています。インデントスペースがいくつあるかを追跡する必要があるため、それらを特別な「変数」に格納する必要があります。これを行うには、グループキャプチャを使用します。これにより、「(」の後に始まり、「)」の前に終わる試合の部分が保存されます。したがって、これを使用して、行の開始後、開き角かっこの前のスペースをキャプチャします。次に、開き角かっこに続いてスペースとそれぞれの閉じ角かっこを一致させます。置換を作成するときは、一致の最初のグループキャプチャによって保存されたデータを含む特別な変数「\ 1」を使用して、スペースを再挿入してください。次に、それぞれの開き括弧と閉じ括弧のペア、およびエスケープされた改行を書き込みます。

なんとか置換を行うことができた場合は、今書いたものを印刷し、パターンスペースから削除して、行の残りの文字でループを再開する必要があります。このため、最初に「t」コマンドを使用して「will_loop」ラベルに分岐します。それ以外の場合は、「only_open」ラベルに分岐します。これは、連続するそれぞれの閉じ括弧なしで、開いた括弧のみの場合を処理します。

「will_loop」ラベル内では、「P」コマンドを使用して、最初の改行(手動で追加)までのパターンスペースのすべてを印刷します。次に、最初の改行までのすべてを手動で削除して、残りの行を続行できるようにします。これは「D」コマンドの機能と似ていますが、スクリプトの実行を再開しません。最後に、ループの先頭に再び分岐します。

「only_open」ラベル内では、以前と同様の方法で開き角かっこを一致させますが、ここでは改行を追加して書き直します。次に、その行を印刷して、パターンスペースから削除します。ここで、すべての角かっこ(開きまたは閉じ、正方形または通常)を、先頭に1つのスペース文字が付いたものに置き換えます。これは、インデントをインクリメントできるようにするためです。最後に、ループの先頭に再び分岐します。

最後のラベル「close」は、閉じ括弧を処理します。まず、角かっこの前のすべてのスペースを削除して、インデントを効果的に減らします。これを行うには、キャプチャを使用する必要があります。これは、スペースとそれに続くブラケットを一致させたいが、ブラケットを書き戻すだけであるためです。最後に、「閉じる」ラベルを入力する前に手動で追加した改行まですべてを印刷し、パターンスペースから印刷したものを削除して、ループを再開します。

いくつかの観察:

  1. これは、コードの構文上の正確さをチェックしません(つまり、{{[}]は受け入れられます)
  2. タイプに関係なく、角かっこが検出されると、インデントが追加および削除されます。これは、インデントを追加すると、検出された閉じ括弧が同じタイプでなくても、インデントを削除することを意味します。

これがお役に立てば幸いです。長い投稿をお詫びします=)

于 2012-09-26T03:21:55.707 に答える
3

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

sed 's/[^][{}]//g;s/./&\n/g;s/.$//' file |
sed -r '/[[{]/{G;s/(.)\n(.*)/\2\1/;x;s/^/\t/;x;b};x;s/.//;x;G;s/(.)\n(.*)/\2\1/' |
sed -r '$!N;s/((\{).*(\}))|((\[).*(\]))/\2\5\3\6/;P;D'

説明:

  1. 最初のsedコマンドは、それぞれ独自の行に中括弧/角括弧のストリームを生成します
  2. 2番目のsedコマンドは、各ブラケットをインデントします
  3. 3番目のsedコマンドは、これらのペアのブラケットを1行に減らします

正しくインデントされた角かっこに満足している場合は、3番目のコマンドを省略できます。

于 2012-09-26T09:18:45.617 に答える
2

期待される出力は次のようになると思います。

{
-{
--[]
-}
-{
-}
}

使用する1つの方法は次のGNU awkとおりです。

awk -f script.awk file.txt

内容script.awk

BEGIN {
    FS=""
    flag = 0
}

{
    for (i=1; i<=NF; i++) {
        if ($i == "{" || $i == "[") {
            flag = flag + 1
            build_tree(flag, $i)
            printf (flag <=2) ? "\n" : ""
        }
        if ($i == "}" || $i == "]") {
            flag = flag - 1
            printf (flag >= 2) ? $i : \
                build_tree(flag + 1, $i); \
                printf "\n"
        }
    }
}

function build_tree (num, brace) {
    for (j=1; j<=num - 1; j++) {
        printf "-"
    }
    printf brace
}
于 2012-09-26T03:46:51.487 に答える
2

これは古代のスレッドであり、とにかく誰も見ていませんが、今はもっと簡単な方法があります。

cat file.txt | jq'。' | sed's / /-/ g'| tr -dc'[[] {}()] \ n-' | sed'/ ^-* $ / d'

最初のsedには2つのスペースがあります。

于 2015-05-18T22:55:20.257 に答える