web-dev-qa-db-ja.com

二重引用符内にあるコンマのみを削除します

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

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ソリューションを投稿していただければ幸いです。

10
Avinash Raj

@riciのPerlの方がはるかに単純ですが、これは here から変更されたもので、必要なことを実行するはずです。

_$ 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-9_または_,_の0以上に一致し、その後に0または1 _,_が続きます。
    • _("[0-9,]*",?)*_:上記の0以上に一致します。
    • _"[0-9,]*_:_0-9_の直後にある_,_または_"_の0以上に一致
  • _ta;_:ラベルaに戻り、再度実行しますif置換が成功しました。
  • _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などのプログラミングをしたほうがよいでしょう。

7
terdon

Perlに問題がない場合は、短い(そしておそらく単純であるとは限らないが、おそらく高速です)方法があります。

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

_s:::_演算子へのeフラグ(これは_s///_を記述するもう1つの方法です)により、置換は毎回評価される式として扱われます。その式は、正規表現(すでに引用符が抜けている)から_$1_キャプチャを取得し、(_y///_として(_tr///_)とも記述できる)変換します(_/d_)すべてのコンマ。翻訳の数ではなく、翻訳された文字列の値を取得するには、rフラグからyへのフラグが必要です。

どういうわけかPerlにだまされたと感じる人のために、ここにpythonと同等のものがあります。 Pythonは、実際にはシェルのワンライナーツールではありませんが、場合によっては連携して動作するように調整できます。以下は(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
_
10
rici

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"
6
glenn jackman

ブロッククォート

こんにちはPythonのコードは、コンマを二重引用符で置き換えます。コンマはパイプ(|)文字に置き換えられます

これはPythonコードは、二重引用符で囲まれたコンマを置き換えることです

例:x、y、z、1,2、 "r、e、t、y"、h、8,5,6

パイプと置き換える場合x、y、z、1,2、 "r | e | t | y"、h、8,5,6

nullに置き換えた場合x、y、z、1,2、 "rety"、h、8,5,6

writingFile = open('FileToWrite', 'w')
with open('FileToRead') as f:

    while True:

        c = f.read(1)
        if not c:
            print ("End of file")
            break
        print ("Read a character:", c)


        if c=='"':
            writingFile.write(c) 
            c = f.read(1)
            while c != '"':
                if c== ',':
                    c= '|'
                writingFile.write(c)
                c = f.read(1)


        writingFile.write(c)


writingFile.close()
0