web-dev-qa-db-ja.com

テキスト内の数字が連続していない場合にいくつかの記号を追加する方法(または改行を追加する方法)

例:

入力ファイル

A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
A_D2<6>
A<9>
A_D2<10>
A<13>

望ましい出力:

A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>

山かっこ内の数値に注意してください。

数が連続的でない場合は、数が有効であるまで、いくつかの記号を追加します(または改行を追加します)。

この場合、番号5、7、8、11、12はありません。

誰かがawkまたはsed(grepでも)コマンドを使用してこの問題を解決できますか?

私はLinuxの初心者です。コマンドライン全体の詳細を説明してください。

7
yen

これを行うためにgrepまたはsedを使用することはお勧めしません。grepはカウントできず、sedは本当にだからですあらゆる種類の計算を行うのは困難です(正規表現ベースのカウントである必要があります 専用 を除くほとんどの人にとってスターターではありません)。

$ awk -F '[<>]' '{ while ($2 >= ++nr) print "---"; print }' file
A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
---
A_D2<6>
---
---
A<9>
A_D2<10>
---
---
A<13>

awkコードは、0が最初の数値であると想定し、現在の行のwanted行番号を維持します変数nr内。 1つまたは複数の行を挿入する必要がある数値が入力から読み取られる場合、これはwhileループ(nr変数もインクリメントする)によって行われます。

<...>内の数値は、<および>をフィールド区切り文字として使用するように指定することによって解析されます。番号は$2(2番目のフィールド)になります。

11
Kusalananda

これはおそらく効率的ではありません...

$ tr '<' '\t' < testfile | tr '>' ' ' \
  | awk '{ while (NR + shift <= $2) { print "-----"; shift++ }; print }' \
  | tr '\t' '<' \
  | tr ' ' '>'
A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>

最初に、trを使用して、ファイルから2つのタブ区切りフィールドを取得します。

次に、もう一度trを使用して「>」をスペースに置き換えます。そうしないと、awkコマンドが失敗するためです:-/

このあたりのawkの専門家はおそらく笑うでしょう:-)

3番目に、awk-コマンドは、処理された行数を2番目のフィールドと比較します。行数が少ない場合は、マーカーが印刷され、前の比較の行数に追加されるshiftが増加します。

4番目と5番目:以前にtrで行った変更を元に戻します。

https://unix.stackexchange.com/a/190707/364705 からインスピレーションを得ました

4
markgraf

私はawkの人ではありませんが、これもそうしているようです。私は常に改善の余地があります。

awk -F '[<>]' -v num=0 '
{
  while(num < $2) {
    print "----";
    num++
  }
  print $1"<"$2">"
  num++
}' file

最初に、フィールド区切り文字を<および>の文字と一致するように設定し、各行がこれらの文字で分割されるようにします。たとえば、最初の行は$1=A$2=0に割り当てられます。

次に、変数num=0を設定します。これを行カウンターとして使用します。現在の行の番号$2が行カウンターより大きい場合は、----を出力し、両方の値が等しくなるまでカウンターを繰り返します。次に、$1<$2>を出力し、カウンターをインクリメントします。

2
Freddy

最初の行の数字がゼロでない場合でも、最初の行の前に破線を印刷しないようにするには、次のようにします。

$ cat tst.awk
BEGIN { FS="[<>]+" }
{
    curr = $(NF-1)
    if ( NR > 1 ) {
        for (i=prev+1; i<curr; i++) {
            print "-----"
        }
    }
    print
    prev = curr
}

$ awk -f tst.awk file
A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>
1
Ed Morton

先読みと後読みを使用し、ダッシュのみを追加する正規表現を使用して、この問題に対処できます。

$ Perl -0777 -pe 's/^.*<(\d+)>.*\n\K(?=.*<(\d+)>.*$)/qq[-----\n] x ($2-$1-1)/gem' file

結果:

A<0>
A<1>
A_D2<2>
A_D2<3>
A<4>
-----
A_D2<6>
-----
-----
A<9>
A_D2<10>
-----
-----
A<13>
1
Rakesh Sharma