,
テキストファイルから(カンマ)と(引用符)を削除したい"
(二重引用符にカンマ区切りの数字が含まれている場合のみ)。
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が大丈夫なら、ここに短い(必ずしも簡単ではありませんが、おそらく高速です:))方法があります:
perl -pe 's:"(\d[\d,]+)":$1=~y/,//dr:eg' file
e
演算子のフラグ(s:::
作成する別の方法s///
)は、置換が毎回評価される式として処理されるようにします。この式は$1
正規表現(すでに引用符がありません)からキャプチャを取得し、すべてのカンマ(y///
、で書くこともできます)を削除()して変換します。 (翻訳数の代わりに)翻訳された文字列の値を取得するには、toフラグを使用する必要があります。tr///
/d
r
y
Perlに汚染されていると感じる人のために、Pythonと同等のものがあります。 Pythonは実際には1行のシェルではありませんが、時には協力するように導くことができます。以下は1行で書くことができますが(for
できないループとは異なり)、水平スクロールを使用すると読み取りが(さらに)難しくなります。
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
will befoobar
、\2
will bebar
。 "[0-9,]*",?
:0個以上の0-9
orと一致し、,
その後に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
上記のコードでは、数字が認識され、挿入されたコンマが削除されました。正規表現は次の事実を利用します。入れ子構造\" ~ \" [\d+]
これは、「二重引用符」で囲まれた1つ以上の数字を意味するRakuの新しい〜チルダ(入れ子)表記を使用して表現できます。
また、繰り返し構造%
Rakuの新しいバリエーション反復構造数量子を使用して表現できます。表記 [\d+] ** 2..* % "," は、1 つ以上の,
カンマで区切られた数字を意味します。 このパターンは** 2..*
複数回繰り返されます。構文では、%%
]の代わりにaを使用してください。%
これは始まりに過ぎません。代替区切り文字、挿入された改行、挿入されたカンマ、空のフィールドなどを含むCSVファイルは、実際にはText::CSV
実際のCSVパーサー(Rakuモジュールなど)で処理する必要があります。詳しくは下記リンクをご覧ください。
https://docs.raku.org/言語/regexes
https://raku.land/github:Tux/Text::CSV
https://raku.org