CSVファイル内の二重引用符で囲まれた数字内のカンマのみを削除します

CSVファイル内の二重引用符で囲まれた数字内のカンマのみを削除します

,テキスト ファイルで、 (カンマ) と(引用符)を削除したいです"(二重引用符内にカンマで区切られた数字が含まれている場合のみ)。

56,72,"12,34,54",x,y,"foo,a,b,bar"

期待される出力

56,72,123454,x,y,"foo,a,b,bar"

注記:上記の行は単なる例として示しています。私のテキストファイルには上記のような行が多数含まれており、二重引用符内のカンマで区切られた数字は変化するはずです。つまり、

56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"

期待される出力:

56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

二重引用符内には、カンマで区切られた数字がいくつか存在しますn。また、文字を含む二重引用符はそのままにしておきます。

私はテキスト処理ツールが大好きですsed。これに対する解決策を投稿していただければ幸いですsed

答え1

perl が OK なら、これを行うための短い (必ずしも簡単ではないかもしれませんが、おそらく高速です :) ) 方法は次のとおりです。

perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file

e演算子のフラグ(s:::の別の書き方s///) により、置換は毎回評価される式として扱われます。その式は、$1正規表現 (すでに引用符が欠落しています) からキャプチャを取得し、すべてのコンマを削除して ( ) 変換します ( y///、 と記述することもできます)。のフラグは、翻訳回数ではなく翻訳された文字列を値として取得するために必要です。tr////dry

Perl に何となく不快感を覚える人のために、Python の同等物を紹介します。Python は実際にはシェルのワンライナー ツールではありませんが、時にはうまく連携させることができます。次のコードは 1 行で記述できます (forループは 1 行で記述できません) が、水平スクロールによって (さらに) 読みにくくなります。

python -c '
import re;
import sys;
r=re.compile("\"(\d+(,\d+)*)\"");
all(not sys.stdout.write(r.sub(lambda m:m.group(1).replace(",",""),l))
    for l in sys.stdin)
' < file

答え2

これは(ここ) で必要な処理は実行できるはずですが、@rici の Perl 版の方がはるかにシンプルです。

$ sed -r ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;ta; s/""/","/g; 
          s/"([0-9]*)",?/\1,/g ' file
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454,
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

説明

  • :a: というラベルを定義しますa
  • s/(("[0-9,]*",?)*"[0-9,]*),/\1/: これは分解する必要がある
    • まず、この構造 : を使用すると(foo(bar))\1となりfoobar\2となりますbar
    • "[0-9,]*",?: 0 個以上の0-9またはに一致し,、その後に 0 個または 1 個が続きます,
    • ("[0-9,]*",?)*: 上記の 0 個以上に一致します。
    • "[0-9,]*0-9:または,の直後に0個以上続く"
  • ta;: ラベルに戻ってa再度実行しますもし置換は成功しました。
  • s/""/","/g;: 後処理。""に置き換えます","
  • s/"([0-9]*)",?/\1,/g: 数字を囲む引用符をすべて削除します。

これは別の例で理解しやすくなるかもしれません:

$ echo '"1,2,3,4"' | sed -nr ':a;s/(("[0-9,]*",?)*"[0-9,]*),/\1/;p;ta;'
"1,2,34"
"1,234"
"1234"
"1234"

したがって、引用符の直後にコンマと別の数字が続く数字を見つけたら、その 2 つの数字を結合して、それが不可能になるまでこのプロセスを繰り返します。

info sedこの時点で、上で使用したラベルなどの高度な機能を説明するセクションに出てくる引用を言及しておくと便利だと思います(@Braiam さん、見つけてくれてありがとう)。

ほとんどの場合、これらのコマンドを使用する場合は、おそらく「awk」や Perl などでプログラミングする方がよいでしょう。

答え3

CSV データの場合は、実際の CSV パーサーを備えた言語を使用します。たとえば、Ruby の場合:

ruby -rcsv -pe '
  row = CSV::parse_line($_).map {|e| e.delete!(",") if e =~ /^[\d,]+$/; e} 
  $_  = CSV::generate_line(row)
' <<END
56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"
END
56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

答え4

使用(旧称 Perl_6)

~$ raku -pe 's:g/ \" ~ \" (\d+) ** 2..* % "," /{$0.join}/;'  file

サンプル入力:

56,72,"12,34,54",x,y,"foo,a,b,bar"
56,92,"12,34",x,y,"foo,a,b,bar"
56,72,"12,34,54,78,76,54,67",x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar","12,34,54"
56,72,x,y,"foo,a,b,bar","12,34,54","45,57,84,92","bar,foo"

サンプル出力:

56,72,123454,x,y,"foo,a,b,bar"
56,92,1234,x,y,"foo,a,b,bar"
56,72,12345478765467,x,y,"foo,a,b,bar"
56,72,x,y,"foo,a,b,bar",123454
56,72,x,y,"foo,a,b,bar",123454,45578492,"bar,foo"

Raku は、強力な正規表現機能を多数備えた Perl ファミリーのプログラミング言語です。この回答の概要については、以下の URL を参照してください。

https://unix.stackexchange.com/a/722570/227738

上記のコードでは、数字が認識され、埋め込まれたカンマが削除されます。この正規表現は、ネストされた構造Raku の新しい ~ チルダ (ネスト) 表記法で表すことができます。これは、\" ~ \" [\d+]「" 二重引用符で囲まれた 1 つ以上の数字」を意味します。

さらに、繰り返し構造繰り返し構造を表すRaku の新しい修正量指定子で表すことができます%。表記法 [\d+] ** 2..* % "," は、「1 つ以上の数字が,カンマで区切られ、このパターンが 2 回以上繰り返される」ことを意味します** 2..*。[末尾に区切り文字 (カンマなど) がある場合は、構文で%%の代わりにを使用します]。%

これはほんの始まりに過ぎません。代替セパレータ、埋め込まれた改行、埋め込まれたカンマ、空白の可能性のあるフィールドなどを含む CSV ファイルは、Raku のモジュールのような真の CSV パーサーで処理する必要がありますText::CSV。詳細については、以下のリンクを参照してください。

https://docs.raku.org/language/regexes
https://raku.land/github:Tux/Text::CSV
https://raku.org

関連情報