Я работаю с .csv
вывод этого запроса данных SE, который похож на это (только с 5 022 записями):
"{
""id"": 281952,
""title"": ""Flash 11.2 No Longer Supported by Google Play""
}"
"{
""id"": 281993,
""title"": ""Netbeans won't open in Ubuntu""
}"
(И это имеет строку ^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
последовательности кажутся существенно ужасными мне - если необходимо удалить окончания строки DOS, использовать dos2unix
, tr
, или sed 's/\r$//
'
Если Вы настаиваете на том, чтобы использовать sed, то я предлагаю, чтобы Вы распечатали биты, которые Вы действительно хотите, вместо того, чтобы пытаться удалить все случайные биты, которые Вы не делаете - например,
$ 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
Вы могли стать действительно необычными и эмулировать 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 в кавычки, я предложил бы установить надлежащий синтаксический анализатор JSON такой как jq
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 '.[]'
вывести всех пар значения атрибута.
Кредит на вдохновение и основной jq
синтаксис, взятый от Преодоления новых строк с grep-o
Еще три подхода:
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
GNU grep с жемчугом совместимый regexes и простой жемчуг:
$ 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
Это точно не отвечает на Ваш вопрос или решает Вашу проблему, но избавиться от нежелательных символов, которые можно использовать tr:
cat QueryR | tr -d '}{:"'
и Вы доберетесь:
Я зафиксировал его благодаря steeldriver и дальнейшему лужению. Неочищенный, но работы.
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/,\ /}}
соответствие ,\r
на одной строке и [whatever]title[whatever]:
на следующей строке замените все это ,
s/""//g
Удалите все остающиеся двойные двойные кавычки
s/^\s\+//
Удалите пробел из запуска строк
/^\s*$/d
Удалите пустые строки
s/^id:\ //
Удалить id:
и пространство после него
s/\\//g
Удалите обратные косые черты (символы Escape для того, "добавил к некоторым полям заголовка),
tee "$1"
укажите outfile при запущении скрипта, например ./queryclean newquery.csv
В то время как вопрос просит sed
, можно было работать вокруг проблем sed с Python:
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
Это - другой сценарий, записанный в 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"