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


10

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

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この解決策を投稿していただければ幸いです。


以下から56,72,"12,34,54",x,y,"foo,a,b,bar"56,72,123454,x,y,"a,b"fooそしてbar消えています。それはあなたの望む出力ですか?
cuonglm 2014年

使用する例は、いくつかの要素(fooおよびbar)がコンマとともに削除されるため、少し混乱します。さらに、一部のクオートは、他のクオートが残っている場所で消えます。aとの間のコンマもb残っていることは言うまでもありません。これらにパターンはありますか?
HalosGhost 2014年

申し訳ありませんが友達を編集しました。
Avinash Raj 2014

あなたの編集はあなたの例を本当に明確にしていません。私の最後のコメントをください。
HalosGhost 2014年

二重引用符内のすべてのコンマと引用符に数字が含まれている場合にのみ引用符を削除します。
Avinash Raj

回答:


7

これ(ここから適応)は、@ 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-9orに一致し,、その後に0または1が続き,ます。
    • ("[0-9,]*",?)* :上記の0以上に一致します。
    • "[0-9,]*:0個以上に一致する、0-9または,aの直後に来る"
  • 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などのプログラミングのほうが得策です。


10

perlに問題がなければ、ここに短い(そして、必ずしも簡単ではないにせよ、おそらく速い)方法があります。

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

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

どういうわけか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

@rici:いいね!そして、もう1人のキャラクターy///tr///保存する代わりに使用してください。
cuonglm 2014年

6

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"

0

ブロッククォート

こんにちはこれは、二重引用符でコンマを置き換える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()

説明はほとんど必要ありません。
Mongrel 2016

このPythonコードは、二重引用符で
囲ま
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.