私は このSEデータクエリ の.csv
出力を使用しています(これは5022エントリのみ)。
"{
""id"": 281952,
""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
""id"": 281993,
""title"": ""Netbeans won't open in Ubuntu""
}"
(そして、[number]と "" title ""の間に^M
で終わる行があります)。このように見える必要があります:
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
簡単に名前のないテキストエディターでこれを修正しましたが、クエリを更新するたびに他のユーザーが使用できるようにスクリプトを作成したいと思いました。 sed
...を使用しました.
この一連のコマンドは完全に機能します(ただし、非効率的かもしれませんが、単なる試行錯誤のソリューションです)。
# Print the ^M and remove them, write to a new file:
cat -v QueryR* | sed 's/\^M//' > QueryNew
# remove all the other junk:
sed -i 's/{//' QueryNew
sed -i 's/}//' QueryNew
sed -i 's/""//g' QueryNew
sed -i 's/^"//' QueryNew
sed -i '/,/{N;/\n.*title:\s/{s/,\n.*title:\s/,\ /}}' QueryNew
sed -i 's/^\s\+//' QueryNew
sed -i '/^\s*$/d' QueryNew
sed -i 's/^id:\ //' QueryNew
sed -i 's/,\ /,/' QueryNew
sed -i 's/\\//g' QueryNew
だから、なぜこれはしないのですか? ^M
と{}
のみが削除され、その他はすべてそこにあります。
#!/bin/bash
cat -v QueryR* | sed 's/\^M//' > QueryNew
sed -i '{
s/{//
s/}//
s/""//g
s/^"//
/,/{N;/\n.*title:\s/{s/,\n.*title:\s/,\ /}}
s/^\s\+//
/^\s*$/d
s/^id:\ //
s/,\ /,/
s/\\//g
}' QueryNew
私の間違いは本当に明らかだと確信しています...
cat -v
を使用してCR文字をリテラル^M
シーケンスに変換することは、基本的にfundamentalいようです。DOSの行末を削除する必要がある場合は、dos2unix
、tr
、またはsed 's/\r$//
を使用してください。
Sedの使用を主張する場合は、不要なビットをすべて削除しようとするのではなく、必要なビットdoを印刷することをお勧めします-例えば
$ sed -rn -e 's/\"//g' -e 's/(.*): (.*)\r/\2/p' QueryR | paste -d '' - -
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
値シーケンスの各端でゼロ個以上の引用符を照合することにより、空想を得て、引用符の削除をキー値抽出に組み込むことができます
$ sed -rn 's/(.*): \"*([^"]*)\"*\r/\2/p' QueryR | paste -d '' - -
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
really空想を取得し、paste
のsed
をエミュレートするには、最初に,\r$
の行のペアを結合してから、キーと値のペアを乗算します(g
)と貪欲ではない
$ sed -rn '/,\r$/ {N; s/([^:]*): \"*([^:"]*)\"*\r\n?/\2/gp}' QueryR
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
(個人的にはKISSアプローチを好み、最初のアプローチを使用します)。
FWIW、入力がJSONを過剰に引用しているように見えるため、jq
などの適切なJSONパーサーをインストールすることをお勧めします
Sudo apt-get install jq
その後、次のようなことができます
$ sed -e 's/["]["]/"/g' -e 's/"{/{/' -e 's/}"/}/' QueryR | jq '.id, .title' | paste -d, - -
281952,"Flash 11.2 No Longer Supported by Google Play"
281993,"Netbeans won't open in Ubuntu"
余分な引用符を削除してからjq
を使用して目的のフィールドを抽出します。jq
はDOSスタイルの行末を処理しているように見えるため、これらを削除するために特別な手順を実行する必要はありません。
jq '.[]'
に変更して、すべての属性と値のペアをダンプします。
grep -oによる改行の克服 からのインスピレーションと基本的なjq
構文の功績
スチールドライバーとさらにいじくり回したおかげで修正しました。洗練されていないが動作します。
sed '{
s/"{//
s/}"//
s/^"//
/,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,/}}
s/""//g
s/^\s\+//
/^\s*$/d
s/^id:\ //
s/\\//g
}' QueryR* | tee "$1"
翻訳:s/"{//
削除"{
s/}"//
削除}"
s/^"//
行の先頭から"
を削除/,\r/{N;/\n.*title.*:\s/{s/,\r\n.*title.*:\s/,\ /}}
は1行で,\r
と一致し、次の行で[whatever]title[whatever]:
と一致し、すべてを,
で置き換えますs/""//g
残りの二重二重引用符をすべて削除しますs/^\s\+//
行の先頭から空白を削除します/^\s*$/d
空行を削除s/^id:\ //
id:
とその後のスペースを削除しますs/\\//g
バックスラッシュを削除します(一部のタイトルフィールドに追加された "のエスケープ文字)tee "$1"
スクリプトの実行時にoutfileを指定します。たとえば、./queryclean newquery.csv
質問はsed
を要求しますが、Pythonでのsedの問題を回避できます。
from __future__ import print_function
import sys
with open(sys.argv[1]) as f:
for line in f:
if '""id""' in line:
print(line.strip().split(':')[1],end="")
if '""title""' in line:
title = " ".join(line.strip().split(':')[1:])
print(title.replace('""'," "))
このコードはpython2とpython3の両方に準拠しているため、どちらも機能します
サンプル実行:
bash-4.3$ cat questions.txt
"{
""id"": 281952,
""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
""id"": 281993,
""title"": ""Netbeans won't open in Ubuntu""
}"
bash-4.3$ python3 parse_questions.py questions.txt
281952, Flash 11.2 No Longer Supported by Google Play
281993, Netbeans won't open in Ubuntu
さらに3つのアプローチ:
awk
$ awk -F'": ' '/\"id\"/{id=$NF;}
/\"title\"/{
t=$NF;
sub(/^""/,"",t);
sub(/""$/,"",t);
print id,t
}' OFS="" file
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
Perl
$ Perl -lne '$id=$1 if /id"":\s*(\d+)/;
if(/title"":\s*""(.*)""/){print "$id,$1"}' file
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
Perl互換の正規表現と単純なPerlを使用したGNU grep:
$ grep -oP '(id"":\s*\K.*)|(title"":\s*""\K.*(?=""))' file |
Perl -pe 'chomp if $.%2'
281952,Flash 11.2 No Longer Supported by Google Play
281993,Netbeans won't open in Ubuntu
これは、Rubyで記述された別のスクリプトです。タイトルにカンマが保持され、列を壊さずにスプレッドシートプログラムに簡単にインポートできます。
csvfile = File.open('query-fixed.csv', 'w')
File.open('QueryResults2.csv') do |f|
content = f.read
content.gsub!(/\r\n?/, "\n")
content.each_line do |line|
id, title = '', ''
if line.match('\"id\"')
id = line.split(':')[1].strip[0..-2]
csvfile.write(id + ',')
end
if line.match('\"title\"')
title = line.partition(':')[2].scan(/"(.*)"/)[0][0]
csvfile.write(title + "\n")
end
end
end
プログラムの実行後、生成された出力は次のようになります
281952,"Flash 11.2 No Longer Supported by Google Play"
281993,"Netbeans won't open in Ubuntu"