vim正規表現の検索と置換

vim正規表現の検索と置換

ファイルの文字列の一部を置き換えようとしています。

たとえば、csvファイルがあります。

r1,col1,col2,35,000,col4,col5
r2,col1,col2,1,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4,325.33,col4,col5

本質的に上記のcol3を交換したいと思います。また、次のように最初のx数を維持します。

r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5

通常私は処刑をします。

:%s/\,[0-9]*\,/\,\1/g

しかし、私が走ると私は得ます。

r1,col1,col2,000,col4,col5
r2,col1,col2,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,325.33,col4,col5

必要な出力を得るには、交換の2番目の部分で何を使用する必要がありますか?

答え1

あなた可能考える:%s/\v(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/

目的は、他の場所からカンマを削除したり、他のテキストを削除したりせずに、4番目のフィールド(存在する場合)からカンマを削除することです。複雑な要素は、カンマがフィールド区切り文字としても使用されることです。この問題を解決するには、フィールド内にコンマが表示される可能性がある条件に関する知識を考慮する必要があります。結局のところ、これ以上の制限がなければ、あなたの記録はあいまいです。

2桁のカンマはすべて削除されると思うのは簡単ですが、そうではありません。あなたの入力例はできる1つのフィールドは数字で終わり、次のフィールドはcol2,35,0001()で始まります。

最初の3つのフィールド自体にカンマが含まれていないことがわかると、問題ははるかに簡単になります。これは、カンマを削除する前に、カンマが続くゼロ以上のカンマではなく、最初の3つのシーケンスをスキップできるためです。そうすれば、問題は、第4次戦がいつ終わったのかをどうやって知ることができるかということになります。削除したいかどうか自分に尋ねてください多くの種類4番目のフィールドにカンマがあるか、常にコンマがないか1つがあるか。

この答えのために、4番目のフィールドには、削除する必要がある最大1つのカンマが含まれているとします。また、カンマは 1 つ以上の数字の後、少なくとも 1 つの数字の前に表示されるとします。その後、Vimで使用できます。

:%s/\v(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/

またはSedを使用したい場合:

sed -r 's/(([^,]*,){3})([0-9]+),([0-9])/\1\3\4/' filename.csv

どのように動作しますか?

正規表現は、(([^,]*,){3})最初の3つのフィールドとそれに続くフィールドの区切り文字を一致させ、すべて同じままにしようとします。[^,]を除くすべての単一文字と一致します,。これにより*、まったく1つではなく0つ以上の一致が生成されます。次の内容は、,コンマではなくフィールドの後の実際のコンマと一致します。これはすべてグループ化さ( )れて{3}適用され、1回ではなく3回一致します。それからそれすべてがグループ化され、 を使用してアクセスできます\1。 (内部グループもキャプチャしてできる訪問として利用可能です\2。 )

次に、([0-9]+)1つ以上の(+)数字()を一致させてアクセスできるように一致[0-9]()をキャプチャします。( )\3,いいえ維持されます。次に、([0-9])でアクセスできるように数字をキャプチャします\4

単一のグループを使用して正規表現をより簡単にすることができます\1。私はこれがレコードの構造を隠していると感じたので避けました。レコードはカンマ区切りのフィールドで構成されていますが、そうしても問題はありません。これが行われるので、交換モードでは代わりに使用します。\3(([^,]*,){3}[0-9]+)\4\3\1\3\1\3\4

ついに、これ\vVim 正規表現の先頭で拡張正規表現構文を使用できるようにサービス-rに渡されます。sedそれで、andの代わりにandの代わりにand(を書くことができました。)\(\)+\+

答え2

次の正規表現を使用して、vimでこれを行うことができます。

%s/\([^,]\+,\)\{3}[^,]*\zs,\ze[^,]*\(,[^,]\+\)\{2}//

説明は次のとおりです。

  • \([^,]\+,\)\{3}3つのcsvフィールドと次のコンマが正確に一致します。

  • \(,[^,]\+\)\{2}2つのcsvフィールドと前のコンマが正確に一致します。

  • これら2つの式の間の内容は、カンマを削除する必要があるフィールドをキャプチャします。

答え3

$ sed 's/,\([0-9]\+\),\([0-9]\+\)/,\1\2/' input
r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5

使用された表現を説明してください。

  NODE                     EXPLANATION
  ,                        ','
  (                        group and capture to \1:
    [0-9]+                   any character of: '0' to '9' (1 or more
                             times (matching the most amount
                             possible))
  )                        end of \1
  ,                        ','
  (                        group and capture to \2:
    [0-9]+                   any character of: '0' to '9' (1 or more
                             times (matching the most amount
                             possible))
  )                        end of \2

次に、一致を,\1\2

答え4

awkこれに使用できます。このスクリプトは、4番目の列の複数のコンマを処理できます。この場合を処理するためにを使用するのは難しいと思います(複数のカンマがあります)vim。しかし、使いやすいですawk

メモ:このソリューションは6つの列にのみ機能します(r1列も数えています)。

awk '
BEGIN {
    FS = ",";
    OFS = ",";
}
{
    accum = "";
    for(i = 4; i < NF - 1; i++) {
        accum = accum $i;       
    }

    print $1, $2, $3, accum, $(NF - 1), $NF;
}' input.txt

入力(テスト用のターゲットフィールドに複数のカンマを含む行を追加)

r1,col1,col2,35,000,col4,col5
r2,col1,col2,1,000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4,325.33,col4,col5
r5,col1,col2,4,325,250.33,col4,col5
r6,col1,col2,4,100,325,250.33,col4,col5

出力

r1,col1,col2,35000,col4,col5
r2,col1,col2,1000,col4,col5
r3,col1,col2,325.33,col4,col5
r4,col1,col2,4325.33,col4,col5
r5,col1,col2,4325250.33,col4,col5
r6,col1,col2,4100325250.33,col4,col5

関連情報