У меня есть большое количество больших файлов данных, разделенных точкой с запятой. Все строковые поля заключены в двойные кавычки. В некоторых файлах есть дополнительные кавычки в строковых полях, что портит последующий импорт данных для анализа (я импортирую в Stata).

Этот код позволяет мне увидеть проблемные цитаты, используя gnu-awk:

echo '"This";"is";1;"line" of" data";""with";"extra quotes""' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")"}; {for ( i=1 ; i<=NF ; i++ ) if ($i ~ /^"(.*".*)+"$/) {print NR, $i}}'
1 "line" of" data"
1 ""with"
1 "extra quotes""

но я не знаю, как их заменить.

Я думал сделать замену вручную, но оказалось, что в некоторых файлах есть несколько сотен совпадений. Я знаю о функциях awk -sub-, -gsub- и -match-, но я не уверен, как разработать поиск и замену для этой конкретной проблемы.

В приведенном выше примере соответствующие поля должны быть "This" , "is" , 1 , "line of data" , "with" , "extra quotes" , то есть: все точки с запятой являются разделителями, и все кавычки, кроме самых внешних цитаты должны быть удалены.

Должен ли я использовать -sed- или -awk- правильный инструмент? Надеюсь, вы можете помочь мне!

Спасибо,

Matthijs

3 ответа3

1

Один из способов использования GNU awk и FPAT:

awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")" } { for (i=1; i<=NF; i++) if (substr($i,0,1) == "\"" && substr($i,length($i),1) == "\"") { gsub(/"/, "", $i); printf "\"%s\"\n", $i } else { gsub(/"/, "", $i); print $i } }'

Тестирование:

echo '"This";"is";1;"line" of" data";""with";"extra quotes""' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")" } { for (i=1; i<=NF; i++) if (substr($i,0,1) == "\"" && substr($i,length($i),1) == "\"") { gsub(/"/, "", $i); printf "\"%s\"\n", $i } else { gsub(/"/, "", $i); print $i } }'

Результаты:

"This"
"is"
1
"line of data"
"with"
"extra quotes"

Один из способов использования GNU awk , FPAT и GNU sed:

sed -e '/^".*"$/ { s/"//g; s/.*/"&"/ }' -e '/^".*"$/!s/"//g'

Тестирование:

echo '"This";"is";1;"line" of" data";""with";"extra quotes""' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")" } { for (i=1; i<=NF; i++) print $i }' | sed -e '/^".*"$/ { s/"//g; s/.*/"&"/ }' -e '/^".*"$/!s/"//g'

Результаты:

"This"
"is"
1
"line of data"
"with"
"extra quotes"
1

Мое собственное решение, использующее только sed , удаляет все точки с запятой, которые не сопоставляются с разделителями или числовыми полями (команда awk предназначена только для ясности изложения):

echo '"This";"is";1;"line" of" data";""without";"extra quotes""' | sed -E 's/([^;])"+([^;])/\1\2/g' | awk 'BEGIN { FPAT = "([^;]+)|(\"[^\"]+\")"}; {for ( i=1 ; i<=NF ; i++ ) print $i}'
"This"
"is"
1
"line of data"
"without"
"extra quotes"

Я думаю, что это быстрее, так как он работает на полных строках, а не разбивает строку на поля.

1

Я бы предпочел пойти с coreutils и sed (версии GNU):

<<< '"This";"is";1;"line" of" data";""with";"extra quotes""' \
| tr ';' '\n' | sed -r 's/(.)"(.)/\1\2/g' | tr '\n' ';'

Выход:

"This";"is";1;"line of data";"with";"extra quotes";

Он оставляет лишнюю точку с запятой и удаляет символ новой строки, вставляя head -c -1 перед вторым tr и добавляя ; echo чтобы исправить:

tr ';' '\n' | sed -r 's/(.)"(.)/\1\2/g' | head -c -1 | tr '\n' ';'; echo

Выход:

"This";"is";1;"line of data";"with";"extra quotes"

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .