
[code]

    A,"100",Z
    B,"1,000",Z
    C,"1,000,000",Z
    
[/code]

↓

[code]

    A,"100",Z
    B,"1000",Z
    C,"1000000",Z
    
[/code]

に変更したいのですが、sed,awk,linux等ではどのようにするのでしょうか？


CC BY-SA 3.0
2017-07-25T09:48:19.147
36655
2018-01-09T07:44:14.847
2017-07-25T12:00:38.640
49
23889
question
linux sed awk
CSVのデータ内のカンマを削除


Gawk 4.0以降が使えるなら, gawk の FPAT で処理できるようです. ただし, 改行やダブルクオートが含まれているケースには未対応です.

[code]

    $ gawk -v OFS=, -vFPAT='([^,]*)|("[^"]+")' '{for(i=1;i<=NF;i++){if($i~/^[ \t]*"/){gsub(",","",$i)}}; print}'
    
[/code]

[Defining Fields by
Content](https://www.gnu.org/software/gawk/manual/html_node/Splitting-By-
Content.html)とmetropolisさんのコメントを参考にして, 0文字のフィールドにも対応するため, `([^,]+)` の箇所を
`([^,]*)` にしました.

Gawk-4以前しか使えない環境であれば, awkよりも, Cが書きやすいと思います.  
こちらは改行やダブルクオートにも対応しています.

[code]

    #include <stdio.h>
    static int parse_element_quoted()
    {
     int c;
     while((c=getchar())!=EOF) {
      switch (c) {
       case '"':
        c = getchar();
        if(c=='"') {
         // 「"」2個連続するのは元のデータに「"」が1個ある場合.
         // putchar('"'); 「""」から「"」に変換するときはこの行は不要
         putchar('"');
         break;
        }
        else {
         putchar('"'); // 「"」を取るなら不要 (A)
         putchar(c);
         return 0;
        }
       case '\r':
       case '\n':
       // case '\\':
       case ',':
        // ignore (remove) them
        break;
       default:
        putchar(c);
      }
     }
     return 1;
    }
    static int parse_element()
    {
     int c = getchar();
     if(c==EOF)
      return 1;
     else if(c=='"') { 
      putchar('"'); // 「"」を取るなら不要 (B)
      return parse_element_quoted();
     }
     else {
      putchar(c);
      if(c=='\n' || c==',')
       return 0;
      while((c=getchar())!=EOF) {
       switch (c) {
        case ',':
        case '\n':
         putchar(c);   
         return 0;
        case '\r':
         break;
        default:
         putchar(c);   
       }
      }
      return 1;
     }
    }
    int main()
    {
     while(parse_element()==0);
     return 0;
    }
    
[/code]

個人的には, 「,」を削除して一緒に「"」も削除したほうが, 後の処理が楽だと思います.  
その場合は, 上記コードの(A)と(B)の行をコメントアウトしてください.


CC BY-SA 3.0
2017-07-25T11:54:59.373
36660
2017-07-25T11:54:59.373
68
36655
answer


もっと単純に、この書き方でどうでしょう？

[code]

    cat data.csv | awk 'match($0, /".*?"/){tmp0 = substr($0, RSTART, RLENGTH); tmp1 = tmp0; tmp2 = gsub(/,/,"",tmp0); sub(tmp1, tmp0, $0); print $0}'
    
[/code]

1行中に複数の ”で囲まれたデータが来ると処理がおかしくなると思うのですが、私がawkの繰り返し処理がすぐに浮かばないので、以下phpで書きます。

[code]

    $csv_data = '
        A,"100",Z
        B,"1,000","1,000",Z,"1,000"
        C,"1,000,000",Z
        ';
    $array0 = array();
    $end_flag = false;
    
    do{
        $end_flag = false;
        $array = explode('"',$csv_data,2);
        if(count($array) > 1){
            $array0[] = $array[0].'"';
            $array2 = explode('"',$array[1],2);
            if(count($array2) > 1){
                $array0[] = str_replace(',','',$array2[0]).'"';
                $csv_data = $array2[1];
                $end_flag = true;
            }else{
                $array0[] = $array2[0];
            }
        }else{
            $array0[] = $array[0];
        }
    } while($end_flag);
    
    echo implode('', $array0);
    
[/code]


CC BY-SA 3.0
2017-07-26T09:38:54.250
36693
2017-07-26T11:32:45.123
2017-07-26T11:32:45.123
22793
22793
36655
answer


sed だとこんな感じです。ただし、元の文字列にタブ文字を含まないことが前提です。

[code]

    sed '-e s/"\([^"]*\)"/\tA\1\tB/g;:loop;s/\(\tA[^\t]*\),/\1/g;tloop;s/\t./"/g'
    
[/code]

タブ文字をバリアに使い、引用符の開き・閉じを `\tA, \tB` に置換します。  
`\tA` から始まる文字列のカンマをループで一文字ずつ削除して  
削除するものが無くなったら `\tA, \tB` を元の引用符に戻しておしまい。


CC BY-SA 3.0
2017-07-27T03:09:03.053
36707
2017-07-27T03:09:03.053
8431
36655
answer


awkで、フィールドセパレータをダブルコーテーションにしてみました。  
実行ファイル jikko.bat

[code]

    awk -f src.txt < data.csv
    
[/code]

ソースファイル src.txt

[code]

    BEGIN {FS="\"";OFS="\""}
    {gsub(",", "",$2);print}
    
[/code]

ワンライナーの方法を教えて下さい。


CC BY-SA 3.0
2017-07-27T14:36:22.407
36732
2017-07-29T03:26:40.253
2017-07-29T03:26:40.253
17199
17199
36655
answer


ワンライナーだと、そのまんまで改行部分にセミコロンです。

[code]

    awk 'BEGIN {FS="\"";OFS="\""};{gsub(",", "",$2);print}' data.csv
    
[/code]


CC BY-SA 3.0
2018-01-09T07:19:36.563
40833
2018-01-09T07:44:14.847
2018-01-09T07:44:14.847
3060
26927
36655
answer