ファイルの引用符間のデータを置き換える

ファイルの引用符間のデータを置き換える

区切り文字がコンマであるデータファイルから「」の間のデータを抽出したいと思います。

入力ファイルの例:

,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10,000",8/13/2019,

予想出力:

,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10000",8/13/2019,

答え1

これが正しい形式のCSVであると仮定すると(例データはこの点で問題ありません)、次のようcsvformatに使用できます。csvkitフィールド区切り文字をデータにない他の文字に一時的に変更します。たとえば、@すべてのカンマを削除してから、フィールド区切り文字をデフォルト値に戻します。

$ csvformat -D '@' file.csv | tr -d , | csvformat -d '@'
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,10000,8/13/2019,

出力には、変更したフィールドの周りに引用符はありませんが、もはや必要ないからです。

明らかに、「すべてのカンマを削除する」は実際に削除したくないカンマを削除することができるため、7番目のフィールドのカンマのみを選択的に削除できます。

$ csvformat -D '@' file.csv | awk -F '@' 'BEGIN { OFS=FS } { gsub(",", "", $7); print }' | csvformat -d '@'
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,10000,8/13/2019,

答え2

別のawk解決策:

awk -F\" '{
    OFS="\"";
    for ( i = 1; i <= NF; i++ ) {
        if ( i % 2 == 0 ) {
            gsub(/,/, "", $i)
        }
    }
}1' input.csv

次に、二重引用符をフィールド区切り文字として使用し、すべてのフィールドを繰り返します。フィールド番号が偶数の場合(完全ではありませんが、例ではフィールドが引用符の間にあることを意味する必要があります)、フィールドからすべてのコンマが削除されます。これにより、出力フィールド区切り文字で二重引用符を使用してすべての内容が印刷され1ます(変更)。awk

使用中:

$ cat input.csv
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10,000",8/13/2019,
,7/30/2019,7/31/2019,"100",FH/FN 30yr & 20yr TBA & Spec ,"10,000,000",8/13/2019,
,7/30/2019,7/31/2019,"Jack, Mary, and Jane",8/1/2019,"123,456,789,012,345,678","10,000",8/13/2019,
$ awk -F\" '{
>     OFS="\"";
>     for ( i = 1; i <= NF; i++ ) {
>         if ( i % 2 == 0 ) {
>             gsub(/,/, "", $i)
>         }
>     }
> }1' input.csv
,7/30/2019,7/31/2019,Wed,8/1/2019,FH/FN 30yr & 20yr TBA & Spec ,"10000",8/13/2019,
,7/30/2019,7/31/2019,"100",FH/FN 30yr & 20yr TBA & Spec ,"10000000",8/13/2019,
,7/30/2019,7/31/2019,"Jack Mary and Jane",8/1/2019,"123456789012345678","10000",8/13/2019,

メモ:これ〜する数値以外のフィールドからカンマを削除します。 csvファイルを正しく読み取るには、これを行う必要があります。何らかの理由でカンマを保持するには、次の回避策を使用できます。


awk -F\" '{
    OFS="\"";
    for ( i = 1; i <= NF; i++ ) {
        if ( i % 2 == 0 && $i ~ /[0-9]/ ) {
            gsub(/,/, "", $i)
        }
    }
}1' input.csv

答え3

たとえば、次のようになりますawk

cat oldfile | awk '{ print gensub ("(,\"[0-9]+),([0-9][0-9][0-9]),?([0-9][0-9][0-9])?,?([0-9][0-9][0-9]),?","\\1\\2\\3\\4","g");}' > newfile

これは大容量データにも当てはまります。

説明する:

awkプログラム可能なフィルタです。コマンドライン(外側の一重引用符 "'"の間)で指定されたコマンドは、ファイル内の各入力行に対して実行されます。

awkプログラムは次のとおりです(他の形式):

{
    print gensub ("(,\"[0-9]+),([0-9][0-9][0-9]),?([0-9][0-9][0-9])?,?([0-9][0-9][0-9]),?",
                  "\\1\\2\\3\\4",
                  "g");
}

-buildinawkコマンドは、gensub最初の引数に指定された内容を 2 番目の引数に指定された代替項目に置き換えます。 3番目の引数が「g」または「G」で始まる文字列である場合は、すべての項目を置き換えます(見つからなくなるまで試してください)。

置き換えられるものは何ですか?最初の引数は二重引用符で囲まれた正規表現(qv)です。次の部分は次のとおりです。,\次に、[0-9]+1回以上繰り返される数字0〜9を示します(接尾辞演算子+)。,これは1文字だけで、その後に[0-9][0-9][0-9]カンマが,続き、その後に質問が続きます。表示?(これは最初の部分が何を意味するのかを知っていますが、サフィックスは?新しいものです。カンマ数字は省略できます)。その後、より多くの数値グループと省略できるコンマがあります。これはより大きな数字です。

今回の説明ではこれまでかっこ(を省略しました!)これは表現と一致しますが、覚えているものを示します。 2番目の引数では、最初から4番目の一致する項目(数字)をgensub引用し、そこから再印刷します。\1\4

答え4

sed '/\"/,/\"/s/,//'指定したアドレス範囲は、行内の範囲ではなく行範囲のみをフィルタリングするため、試行は失敗します。

このタイプの使命は標準では面倒ですsed。カンマだけがsed -E 's/("[0-9]*),([0-9]*")/\1 \2/問題を解決しますが、複数のカンマがある場合は繰り返す必要があるため、次のような醜い結果が出ます。

sed -Ee :loop -e 's/("[0-9 ]*),([^"]*")/\1 \2/;tloop'

開いた二重引用符の後にランダムな桁が続き、置換に引用されており、コンマの後の("[0-9]*)すべての項目と最後まで一致するため、同じですが、最初のカンマを置き換えます。\1([^"]*")"\1 \2

これで交換が行われると、tコマンドはタグに分岐します。loopこれ以上置き換えるコンマがなくなるまでこれを繰り返します。

これは複数の数字と必要な数のカンマ,7/30/2019,"99,999,999,999,999",0,1 ,"10,000","foo, bar"としても機能します。,7/30/2019,"99 999 999 999 999" 0 1 "10 000" "foo, bar"

関連情報