CSVファイルの部分文字列を特定の長さに切り捨てます。

CSVファイルの部分文字列を特定の長さに切り捨てます。

以下のファイルがあります。Test.csv

"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,

修正後:

cat Test.csv

"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,

これサム""で区切られた部分文字列を含むrdフィールドは、その部分;文字列で置き換える必要があります。

答え1

以下が使用されますcsvkit参照フィールドにカンマを含むCSVデータを直接解析すると、awkエラーが発生しやすいためです。

これにより、正しい形式の3番目の列が生成されます。

csvcut -c 3 file.csv |
sed -r 's/^"|"$//g' |
awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' >tmp-3rd

与えられた入力に対して、これは以下を生成します。

"AB;xy;15"
"C4;x2;rt"
  • csvcut3番目の列が切り捨てられます。
  • sedすべての二重引用符が行の最初または最後に表示されると、データから削除されます。
  • プログラムは、区切りフィールドをawk繰り返してフィールド;ごとに2文字の長さに短縮します。二重引用符でデータを印刷します。
  • 出力はファイルに書き込まれますtmp-3rd

次に、元のデータに再組み立てします(これは、手続き型置換をbash実行するために使用できる別のシェルであると仮定します<(...))。

paste -d, <( csvcut -c 1,2 file.csv ) tmp-3rd <( csvcut -c 4,5 file.csv ) | csvformat
  • paste列はカンマで区切られ、一緒にグループ化されます。
  • 最初のプロセスは元のファイルの最初の2つの列を置き換え、2番目のプロセスは最後の2つの列を置き換えます。中央には、修正された3番目の列があります。
  • csvformatオプションのステップとして、必要に応じてフィールドを参照または逆参照してデータを渡します。

出力は次のとおりです

pav,12345,AB;xy;15,,
xyz,,C4;x2;rt,,

一時ファイルの必要性をバイパスします。

paste -d, \
    <( csvcut -c 1,2 file.csv ) \
    <( csvcut -c 3 file.csv | sed -r 's/^"|"$//g' |
       awk -F';' -vOFS=';' '{ for (i=1; i<=NF; ++i) $i = substr($i, 0, 2) } { printf("\"%s\"\n", $0) }' ) \
    <( csvcut -c 4,5 file.csv ) | csvformat

答え2

そしてperl

;3番目のフィールドでのみ仮定

$ perl -pe 's/"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
  • "\K"関心文字列の前と関心文字列の後に一致します(?=")"ただし、"これは予測文字列なので、キャプチャ文字列自体の一部ではありません。
  • [^;"]*;[^"]*;-OR以外の"文字の後に非;文字"が続くものと一致します。
  • $&=~s|([^;]{2})[^;]+|$1|gr一致する文字列に対して別の置換を実行します。
  • eModifierを使用すると、交換部品にPerlコードを使用できます。


3番目のフィールドのみを制限

$ cat ip.txt 
"pav",12345,"ABCD,EF;xyz23;15rtg",,
"xyz",,"C4DEF;x23yu;rtg",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"

$ perl -pe 's/^("[^"]*",|[^,]*,){2}"\K[^;"]*;[^"]*(?=")/$&=~s|([^;]{2})[^;]+|$1|gr/e' ip.txt
"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,
"foo;12,23;good",124,253
12,5232,"xyz","ijk;5545;62"

答え3

正確で堅牢Python3.xソリューション(ベースcsv.reader目的):

parse_csv.pyスクリプト:

import csv, sys
with open(sys.argv[1]) as f:
    reader = csv.reader(f)
    for l in reader:
        l = [s if ';' not in s else ';'.join(_[:2] for _ in s.split(';')) for s in l]
        print(','.join(i if not i or i.isnumeric() else '"{}"'.format(i) for i in l))

使用法:

python3 parse_csv.py Test.csv

出力:

"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,

Pythonのモジュールは、csvデータの強力で柔軟なサポートを提供します。csv

答え4

複雑なGNUAWKソリューション(csvデータ解析):

awk -v FPAT='"[^"]+"|[^",]+|,,' '{ 
           for (i=1;i<=NF;i++) { 
               if ($i~/^".*;./) { 
                   len=split($i,a,";"); v=substr(a[1],1,3); 
                   for (j=2;j<=len;j++) v= v";"substr(a[j],1,2);
                   v=v"\042"
               }  printf "%s%s",(v? v: ($i~/^,,/? (i==NF? ",":""):$i )),
                                (i==NF? ORS:OFS); v="" 
           } 
       }' OFS=',' Test.csv
  • FPAT='"[^"]+"|[^",]+|,,'- フィールド値の複雑な正規表現パターンの定義

  • if ($i~/^".*;./) ...- 現在のフィールドに文字が$i含まれている場合;

  • len=split($i,a,";")- フィールド値を$i区切り記号として配列に分割します。生成された要素/ブロックの数が割り当てられます。a;len

  • v=substr(a[1],1,3);- 先頭文字を含む必要な長さの最初のブロックをキャプチャします""ABから抽出されます"ABCD,EF

  • for (j=2;j<=len;j++) ...- 残りのチャンク/アイテムを繰り返します。

  • v=v"\042"-"処理されたシーケンスに末尾の二重引用符を追加しますv\043二重引用符で囲まれたcharを表すASCII 8進コード"

  • ($i~/^,,/? (i==NF? ",":""):$i )- 各空のフィールドは、単一のカンマと共通の区切り文字を使用して,,再生成されます。これは不要なコンマの混乱を避けるためです。,,"pav",,,

  • (i==NF? ORS:OFS)- 最後のフィールドが見つかった場合i==NF- レコード区切り文字を印刷しORS、それ以外の場合 - フィールド区切り文字を印刷します。OFS


出力:

"pav",12345,"AB;xy;15",,
"xyz",,"C4;x2;rt",,

関連情報