Удалить запятую из цитируемого текста в первом столбце CSV с помощью sed - PullRequest
0 голосов
/ 05 марта 2019

У меня есть big_file.csv, содержащий кучу информации о компании.Вот фрагмент

CompanyName, CompanyNumber,RegAddress.CareOf,...
"! # 1 AVAILABLE LOCKSMITH LTD","05905727","",...
"!NSPIRED LIMITED","06019953",""...
"CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD","07981734",""...

Мне нужны только поля CompanyName и CompanyNumber, поэтому я сделал следующее:

cut -d, -f 1,2 big_file.csv > big_file_names_codes_only.csv

Как вы можете видеть (и я понимаю, почему) третью записьв big_file.csv вырезается после первой запятой, которая на самом деле является частью CompanyName.Я знаю, как удалить в sed первую запятую (но это сломало бы всю структуру csv), поэтому мне было интересно, знает ли кто-нибудь из вас, как убрать запятую с первой (она всегда находится в позиции 1) "string, with, commas, or not and non alphanum chars!".

Таким образом, в основном промежуточный вывод, который я ищу:

CompanyName, CompanyNumber
"! # 1 AVAILABLE LOCKSMITH LTD","05905727"
"!NSPIRED LIMITED","06019953"
"CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD","07981734"

Но эта последняя строка становится такой:

"CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD"

Как только я получу этот промежуточный вывод, мне нужноочистить компанию от всех не буквенно-цифровых символов в имени и ведущих пробелах - что очень хорошо работает с этим:

sed -i 's/[^a-zA-Z0-9 ,]//g; s/^[ \t]*//'

В конце мой файл должен быть:

CompanyName, CompanyNumber,RegAddress.CareOf,...
AVAILABLE LOCKSMITH LTD,05905727
NSPIRED LIMITED,06019953
CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD,07981734

Ответы [ 10 ]

3 голосов
/ 05 марта 2019

Всегда лучше работать со структурированными данными, такими как CSV-файлы со встроенными запятыми в полях, используя инструменты, которые на самом деле знают о формате, вместо того, чтобы пытаться что-то взламывать вместе с такими вещами, как регулярные выражения (то же самое с XML, JSON и т. Д.),В конечном итоге это будет намного проще и избавит вас от огромного труда, связанного с крайними случаями и странными данными, которые не совсем соответствуют вашим ожиданиям.

Набор утилит csvkit имеетнабор полезных инструментов командной строки, которые обычно доступны через менеджеры пакетов ОС:

$ csvcut -c CompanyName,CompanyNumber blah.csv                                              
CompanyName,CompanyNumber
! # 1 AVAILABLE LOCKSMITH LTD,05905727
!NSPIRED LIMITED,06019953
"CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD",07981734

Затем вы можете продолжать использовать sed для удаления символов, которые вам не интересны.

(Примечание: мне пришлось избавиться от лишних пробелов в строке заголовка вашего примера данных, чтобы это работало)


Редактировать: Кроме того, версия Perl использует удобный Text :: AutoCSV модуль, который удаляет символы:

$ perl -MText::AutoCSV -e 'Text::AutoCSV->new(out_fields => [ "COMPANYNAME", "COMPANYNUMBER" ],
               read_post_update_hr => sub {
                 my $hr = shift;
                 $hr->{"COMPANYNAME"} =~ s/[^[:alnum:]\s]+//g;
                 $hr->{"COMPANYNAME"} =~ s/^\s+//;
               })->write();' < blah.csv | sed -e 's/"//g'
CompanyName,CompanyNumber
1 AVAILABLE LOCKSMITH LTD,05905727
NSPIRED LIMITED,06019953
CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD,07981734
1 голос
/ 06 марта 2019

Вы можете попробовать с этим sed:

sed -E '
  :A
    s/^("[^,"]*),(.*)/\1\2/
    # label A if CompanyName can have more than 1 comma
    tA
  s/"//g;s/([^,]*,[^,]*).*/\1/
' big_file.csv
1 голос
/ 05 марта 2019

Использование Perl

$ perl -lne ' if($.>1) { /^"(.+?)","(.+?)"/ ;$x=$1;$y=$2; $x=~s/[,]//g; print "$x,$y" } 
             else { print } ' big_file.csv
CompanyName, CompanyNumber,RegAddress.CareOf,...
! # 1 AVAILABLE LOCKSMITH LTD,05905727
!NSPIRED LIMITED,06019953
CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD,07981734

$
1 голос
/ 05 марта 2019

Вы были почти там.

Так как я не знаю, сколько запятых есть в первой строке, но если это только название компании и номер компании, эта команда, вероятно, самая короткая, которую вы можете получить.если вы будете использовать bash:

Самый простой способ избавиться от нежелательных символов - это использовать xargs после запуска xargs -L1, все выглядит лучше:

xargs -L1

Вывод:

CompanyName, CompanyNumber,RegAddress.CareOf,...
! # 1 AVAILABLE LOCKSMITH LTD,05905727,,...
!NSPIRED LIMITED,06019953,...
CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD,07981734,...

Теперь мы можем добавить срез -f1,2,3, который вы пробовали, я думаю

xargs -L1 | cut -d, -f1,2,3

Вывод:

CompanyName, CompanyNumber,RegAddress.CareOf
! # 1 AVAILABLE LOCKSMITH LTD,05905727,
!NSPIRED LIMITED,06019953,...
CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD,07981734

Хорошо, теперь я столкнулся с той же проблемой, что и в вашем примере, мы также получили число за LTD, так как мы добавили nr 3 для сокращения, нонежелательные символы в конце все еще существуют:

Решение, прочитайте файл с помощью sed и направьте его с помощью xargs -L1!

sed 's/,...$//;s/,$//;s/, / /g' big_file.csv

Давайте разберем его:

sed 's/,...$//;s/,$//;s/, / /g' big_file.csv|xargs -L1|cut -d, -f1,2

Конечный результат:

 CompanyName CompanyNumber,RegAddress.CareOf
 ! # 1 AVAILABLE LOCKSMITH LTD,05905727
 !NSPIRED LIMITED,06019953
 CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD,07981734

Редактировать

Поскольку я забыл запятую перед редактированием, я нашел лучшее решение:

sed 's/,\ / /g' big_file.csv|xargs -L1|cut -d, -f1,2
1 голос
/ 05 марта 2019

Аналогично решению @ Sonny, но с использованием функции gsub из awk GNU для обрезки кавычек и запятых из выходных данных в соответствии с ожидаемым выходным значением и для приоритизации полей, заключенных в кавычки, над теми, которые не являются:

awk -vFPAT='("[^"]+")|([^,]*)' -vOFS=, '{for(n=1;n<3;++n)gsub(/^"|"$|,/,"",$n);print$1,$2}' big_file.csv

Это выводит:

CompanyName, CompanyNumber
! # 1 AVAILABLE LOCKSMITH LTD,05905727
!NSPIRED LIMITED,06019953
CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD,07981734
1 голос
/ 05 марта 2019

Решение с awk

$ awk -vFPAT='([^,]*)|("[^"]+")' -vOFS=, '{print $1,$2}' big_file.csv
CompanyName, CompanyNumber
"! # 1 AVAILABLE LOCKSMITH LTD","05905727"
"!NSPIRED LIMITED","06019953"
"CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD","07981734"

Я бы предложил использовать такие языки программирования, как R, Python, Perl для таких задач

0 голосов
/ 07 марта 2019
awk 'NR>1{gsub(/"/,"")sub(/.{4}$/,"")gsub(/!|,$/,"")sub(/, /," ")sub(/.{5}A/,"A")}1' file

CompanyName, CompanyNumber,RegAddress.CareOf,...
AVAILABLE LOCKSMITH LTD,05905727
NSPIRED LIMITED,06019953
CENTRE FOR COUNSELLING PSYCHAPY AND TRAINING LTD,07981734 
0 голосов
/ 06 марта 2019

Основываясь на данных двух ответов ниже, я попробовал несколько подходов:

  1. Следующий работал, но с 4-метровыми строками и несколькими столбцами это было очень медленно:
    • Сначала избавьтесь от лишнего начального пробела во втором столбце с помощью: sed -i '0,/ CompanyNumber/ s//CompanyNumber/' big_file.csv
    • Затем объедините xargs -L1 с csvcut и sed:
      sed 's/,\ / /g' big_file.csv | xargs -L1 | csvcut -c CompanyName,CompanyNumber > big_file_cleaned.csv

Это сработало, но было очень медленно.

  1. Решение на Perl от одного из таких авторов!
    • Первая чистая первая строка с perl: perl -lne ' if($.>1) { /^"(.+?)","(.+?)"/ ;$x=$1;$y=$2; $x=~s/[,]//g; print "$x,$y" } else { print } ' big_file.csv > big_file_clean.csv
    • Затем отфильтруйте только нужные мне столбцы: csvcut -c CompanyName,CompanyNumber big_file_clean.csv > big_file_clean_namecodesonly.csv

СПАСИБО

0 голосов
/ 05 марта 2019

С GNU awk для FPAT:

$ cat tst.awk
BEGIN { FPAT="\"[^\"]+\"|[^,]*"; OFS="," }
NR == 1 { print; next }
{
    for (i=1; i<=NF; i++) {
        gsub(/[^[:alnum:]]+/," ",$i)
        gsub(/^ | $/,"",$i)
    }
    print $1, $2
}

$ awk -f tst.awk file
CompanyName, CompanyNumber,RegAddress.CareOf,...
1 AVAILABLE LOCKSMITH LTD,05905727
NSPIRED LIMITED,06019953
CENTRE FOR COUNSELLING PSYCHOTHERAPY AND TRAINING LTD,07981734

См. Какой самый надежный способ эффективного анализа CSV с использованием awk? , если вам нужно работать с более экзотическими CSV.

0 голосов
/ 05 марта 2019

awk твой друг

возможно, это поможет

➜  ~  awk 'BEGIN {FS="\",\""} { printf "%s, %s \n",$1,$2 }' big_file.csv | tr -d '\"'
CompanyName, CompanyNumber,RegAddress.CareOf,...,
! # 1 AVAILABLE LOCKSMITH LTD, 05905727
!NSPIRED LIMITED, 06019953
CENTRE FOR COUNSELLING, PSYCHOTHERAPY AND TRAINING LTD, 07981734
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...