カンマで区切られたファイルから、引用符内に含まれるカンマのみを削除します。

カンマで区切られたファイルから、引用符内に含まれるカンマのみを削除します。

カンマ()で区切られた入力ファイルがあります,。一部のフィールドはカンマで二重引用符で囲まれています。サンプルラインです

123,"ABC, DEV 23",345,534.202,NAME

二重引用符だけでなく、二重引用符内のすべてのカンマを削除する必要があります。したがって、上記の行は次のように解析する必要があります。

123,ABC DEV 23,345,534.202,NAME

次の使用法を試しましたが、sed期待した結果が得られませんでした。

sed -e 's/\(".*\),\(".*\)/\1 \2/g'

sedそれとも、awk他のUNIXユーティリティに関するクイックヒントはありますか?

答え1

awk引用文のバランスが取れたら、次のように表すことができる引用符の間のカンマを削除する必要があります。

awk -F'"' -v OFS='' '{ for (i=2; i<=NF; i+=2) gsub(",", "", $i) } 1' infile

出力:

123,ABC DEV 23,345,534.202,NAME

説明する

二重引用符でフィールド分割を実行するようにawkに指示します-F"。これは、他のすべてのフィールドが引用符で囲まれたテキストであることを意味します。 forループはgsub他のすべてのフィールドで動作します。グローバル置換の省略形として、","カンマ()を空("")に置き換えます。最後に、1基本コードブロックを呼び出します{ print $0 }

答え2

一つあるいいね回答、sedを一度だけ使用してくださいリング:

echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME'|
  sed ':a;s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /;ta'
123,"ABC  DEV 23",345,534,"some more  comma-separated  words",202,NAME

説明する:

  • :a;追加ポイントのラベルです。
  • s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /3つの閉鎖部品を含めることができます。
    • 最初の2番目:[^"]*,\?\|"[^",]*",\?二重引用符を含めずにコンマが後に続く可能性がある文字列と一致します。またはカンマなしで2つの二重引用符で囲まれた文字列で、後にカンマが続くこともあります。
    • 最初のものより希土類部分前述のパート2の複数の反復で構成され、その後に二重引用符といくつかの文字が続きますが、二重引用符とカンマはありません。
    • 最初のRE部分の後には昏睡状態が続きます。
    • 残りの行に触れる必要はありません。
  • ta:as/のコマンドが一部変更された場合は繰り返されます。

ループが完了したら、以下を追加することもできますs/ */ /g

echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME'|
    sed ':a;s/^\(\([^"]*,\?\|"[^",]*",\?\)*"[^",]*\),/\1 /;ta;s/  */ /g'

二重スペースを抑制します。

123,"ABC DEV 23",345,534,"some more comma-separated words",202,NAME

答え3

バランスの取れた引用符間の複数のカンマも処理する一般的なソリューションには、入れ子になった置換が必要です。私は与えられた入力の各行を処理し、他のすべての引用符ペアのコンマだけを置き換えるソリューションをPerlとして実装しました。

perl -pe 's/ "  (.+?  [^\\])  "               # find all non escaped 
                                              # quoting pairs
                                              # in a non-greedy way

           / ($ret = $1) =~ (s#,##g);         # remove all commas within quotes
             $ret                             # substitute the substitution :)
           /gex'

または簡単に言えば

perl -pe 's/"(.+?[^\\])"/($ret = $1) =~ (s#,##g); $ret/ge'

処理するテキストをコマンドにパイプするか、最後のコマンドライン引数として処理するテキストファイルを指定できます。

答え4

2番目の参照が間違っています。

sed -e 's/\(".*\),\(.*"\)/\1 \2/g'

また、正規表現を使用すると、テキストの可能な最長部分に一致する傾向があります。つまり、文字列に引用符で囲まれた複数のフィールドがある場合、この方法は機能しません。

sedで複数の参照フィールドを処理する方法

sed -e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' -e 's/\"//g'

これはこの問題を解決する方法でもあります。ただし、参照される各フィールドに複数のカンマを含めることができる入力の場合、sedの最初の式は、単一フィールドの最大コンマ内容と同じくらい変更されるまで繰り返す必要があります。出力がまったく。

複数の式でsedを実行することは、複数のsedプロセスを実行し、すべての「tr」をオープンパイプとして実行するよりも効率的です。

ただし、入力形式が正しくないと、望ましくない結果が生じる可能性があります。つまり、入れ子になった引用符、終わらない引用符です。

実行例の使用:

echo '123,"ABC, DEV 23",345,534,"some more, comma-separated, words",202,NAME' \
| sed -e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' \
-e 's/\(\"[^",]\+\),\([^",]*\)/\1 \2/g' -e 's/\"//g'

出力:

123,ABC  DEV 23,345,534,some more  comma-separated  words,202,NAME

関連情報