与えられたパターンをコンマに置き換える

与えられたパターンをコンマに置き換える

内容は次のとおりですtest.txt。通常22列です。

BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,GCCFC 2007-GG9 A-M,FCMT7US,COML MORT TST 2007-GG9,0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,MSC 2007-IQ13 AM,Z01IYUS,MORGAN STNLY CAP I TST 2007-IQ13,0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,BANCO SANTANDER SA, MADRID HO,0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR

問題レコードである22列以上の列を見つけてコンマに置き換えたいと思います。

bcz BANCO SANTANDER SA, MADRID HOはキーワードなので、カンマで区切ってはいけません。カンマなしで使用する必要がありますBANCO SANTANDER SA MADRID HO

ベストアンサー1

どの入力行に21を超えるフィールドがあるかを検出するのは非常に簡単です。例えば

awk -F, 'NF>21' input.txt

それを修正することはそれほど簡単ではありません。スクリプトでは、どのフィールドが false であるか (または、逆にどのフィールドにコンマが含まれてはならないか) わかる簡単な方法がないため、これらの行を手動で編集する必要があります (たとえば、またはvi好みのエディタを使用)。nano

これは、単純な(または複雑な)検索と代替のヒューリスティックではなく、実際の知能を必要とするタスクです。また、データセットに関する実用的な知識が必要です。

だから本当だCSVファイルには引用符の中に文字列フィールドが含まれ、実際のCSVパーサーが引用符で囲んだ文字列フィールドを理解する理由もあります。

引用符で囲まれた文字列フィールドを持つ実際のCSVを生成するために、コンマ区切りのファイルから何でも取得できる場合、処理は次のようになります。たくさん簡単になりました。これがこの問題に対する真の解決策です。問題の源を解決することです。


他の回答では、少なくとも実行する必要のある作業の中には、空白で始まるフィールドを以前のフィールドとマージすることを指摘しています。

これを行うには、入力を正しい形式のCSVに変換する必要があります。たとえば、

$ perl -e '
use Text::CSV qw(csv);
$csv = Text::CSV->new();

while($row = $csv->getline(ARGV)) {

  # merge fields beginning with whitespace with the previous field.
  for ($i=1; $i <= @$row; $i++) {
    if ($row->[$i] =~ m/^\s/) {
      $row->[$i-1] .= "," . $row->[$i];
      $row->[$i] = undef;
    };
  };

  # delete any undef-ed fields    
  @$row = grep{defined $_} @$row;

  $csv->say(STDOUT, $row);
};
' input.txt

メモ:

  • この$csv->getline()コマンドはCSVデータの全行を取得します。これはすべて1行にあるか、複数行の引用文字列のために複数行にわたって分散されています。

    これは、現在の入力ファイルとは特に関係がありませんが(CSVではないため、CSVファイルと少し似ているように見えます)、実際のCSVファイルを扱う場合に便利です。

出力例:

BusinessDate,SourceSystemId,IceIndexId,IceIndexName,ComponentId,ComponentReferenceType,ComponentType,ComponentName,ComponentIssuerCIS,ComponentIssuerName,ComponentWeighting,IceCurveID,IceCurveName,RiskyCurveCIS,OriginalWeighting,DerivedWeighting,indexType,cafName,indexStartDate,indexCurrency,componentCurrency
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,20173QAG6,CUSIP,BOND,"GCCFC 2007-GG9 A-M",FCMT7US,"COML MORT TST 2007-GG9",0.04,19063270,risky_20173QAG6_FCMT7US.usd,FCMT7US,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,11260370,risky_CMBX3_AM_19HGEMAC7.usd,61753JAF6,CUSIP,BOND,"MSC 2007-IQ13 AM",Z01IYUS,"MORGAN STNLY CAP I TST 2007-IQ13",0.04,19059680,risky_61753JAF6_Z01IYUS.usd,Z01IYUS,0.04,0.04,indexCds,index_risky_CMBX3_AM_19HGEMAC7.usd,2010-02-09,USD,USD
2019-09-19,ICEEUR,12345400,risky_itraxx_europe32_14.eur,XSNOREFOB258,ISIN,BOND,NOREFOB_BANCO_SANTANDER_SA,BBDERES,"BANCO SANTANDER SA, MADRID HO",0.008,20286090,risky_bank_bsch_14.eur,BBDERES,0.008,0.008,indexCds,index_risky_itraxx_europe32_14.eur,2019-09-18,EUR,EUR

これにより、4行目の2つの問題フィールドが次にマージされました。"BANCO SANTANDER SA, MADRID HO"

気づくみんなスペースを含むフィールド(およびその他の潜在的に問題のある文字)も二重引用符で囲みます。つまり、出力は正しい形式のCSVです。

これは私たちが知っている問題の1つだけを解決します。私たち(つまり、あなた)がまだ知らない他のものがあるかもしれません。たとえば、追加のカンマがあるかもしれませんが、すぐに続くスペースはないかもしれません。

このスクリプト(アルゴリズムのバリエーションを実装する他の答えと同様)は、残りフィールドは空白文字を含む入力行で始まる必要があります。サンプル入力には何もありませんが、1つのヘッダーと3つのデータ行で構成されるサンプルサイズを想定するのは安全ではありません。

これ本物回避策は前述のとおり残ります。ソースから問題を解決してください。破損したゴミの代わりに正しい形式のCSVを出力してください。


正しく引用されたCSVを生成するためにこの出力を生成するプログラムを取得できない場合は、他のオプションは列区切り文字を使用することです。データにはありません。パイプ文字|、セミコロン;、またはタブ文字(0x09、、、 )は通常区切りCtrl-I文字\tとして適しています。

おすすめ記事