Необязательная цитата csv с gawk

Мне нужно использовать "FPAT" или аналогичную функцию "patsplit" gawk. Но похоже, что на нашем сервере CentOs установлена ​​версия gawk 3.1.5.

Я пробовал обновить gawk с помощью этих команд:

yum update gawk;

И сервер показал: «Нет пакетов, отмеченных для обновления».

Я также попытался переустановить gawk с помощью:

 yum install gawk;

вывод сервера: «Пакет gawk-3.1.5-15.el5.x86_64 уже установлен и последняя версия»

Где мне нужен gawk 4.0 или выше, чтобы использовать эти FPAT ИЛИ patsplit. И зачем мне их использовать? ну, я пытаюсь обработать файл CSV, и кажется, что в файле CSV есть необязательная цитата и встроенная запятая.

Пример:

Из такой строки csv:

this,is,a,"csv,with,embedded coma"

Мне нужно разбить поля вот так:

this

is

a

"csv,with,embedded comma"

А вот и код gawk:

awk '{patsplit("this,is,a,\"csv,with,embedded comma\"",a,"([^,]*)|(\"([^\"]|\"\")+\"[^,]*)",seps); for(i=0;i<length(a);i++) print a[i];}';

Может ли кто-нибудь помочь мне в этом, пожалуйста?


person Anas Bin Numan    schedule 02.01.2013    source источник


Ответы (5)


Попробуйте использовать csvquote в своем конвейере, чтобы упростить интерпретацию данных с помощью awk. Это сценарий, который я написал, который заменяет запятые внутри цитируемых полей непечатаемыми символами, а затем восстанавливает их.

Итак, если ваша команда awk изначально выглядела так:

awk -F, '{print $3 "," $5}' inputfile.csv

... его можно заставить работать с разделителями в кавычках csv следующим образом:

csvquote inputfile.csv | awk -F, '{print $3 "," $5}' | csvquote -u

Код и дополнительную документацию см. На странице https://github.com/dbro/csvquote.

person D Bro    schedule 04.05.2013

Я думаю, мы могли бы использовать match () для получения полей.

вот коды:

awk '{ $0=$0","                                   
while($0) {
  match($0,/ *"[^"]*" *,|[^,]*,/) 
  field=substr($0,RSTART,RLENGTH)            
  gsub(/,$/,"",field)   
  print field
  $0=substr($0,RLENGTH+1)              
}}' file

тест с вашим примером ввода:

kent$  echo 'this,is,a,"csv,with,embedded coma"'|awk '{
$0=$0","                                   
while($0) {
  match($0,/ *"[^"]*" *,|[^,]*,/) 
  field=substr($0,RSTART,RLENGTH)            
  gsub(/,$/,"",field)   
  print field
  $0=substr($0,RLENGTH+1)              
}}'
this
is
a
"csv,with,embedded coma"
person Kent    schedule 02.01.2013

Самое простое - преобразовать запятые вне кавычек во что-то еще, прежде чем приступить к реальной обработке. Например:

$ cat file
this,is,a,"csv,with,embedded coma",and,here,"is,another",one
and,here,"is,another,line"
$
$ awk 'BEGIN{FS=OFS="\""}{for (i=1;i<=NF;i+=2) gsub(/,/,";",$i)}1' file
this;is;a;"csv,with,embedded coma";and;here;"is,another";one
and;here;"is,another,line"

Если вам не нравятся символы ";" в качестве разделителей полей, выберите что-нибудь еще, например управляющий символ или вот пример с использованием новой строки в качестве FS и пустых строк в качестве RS:

$ awk 'BEGIN{FS=OFS="\""; ORS="\n\n"}{for (i=1;i<=NF;i+=2) gsub(/,/,"\n",$i)}1' file
this
is
a
"csv,with,embedded coma"
and
here
"is,another"
one

and
here
"is,another,line"

$ awk 'BEGIN{FS=OFS="\""; ORS="\n\n"}{for (i=1;i<=NF;i+=2) gsub(/,/,"\n",$i)}1' file |
awk -F'\n' -v RS= '{for (i=1;i<=NF;i++) print NR,i,"<" $i ">"}'
1 1 <this>
1 2 <is>
1 3 <a>
1 4 <"csv,with,embedded coma">
1 5 <and>
1 6 <here>
1 7 <"is,another">
1 8 <one>
2 1 <and>
2 2 <here>
2 3 <"is,another,line">

Это становится сложно, только если вы встроили символы новой строки или экранированные двойные кавычки.

person Ed Morton    schedule 02.01.2013
comment
Ооо, +1 за замену в каждом втором поле через кавычки! Я оставлю это. :) - person ghoti; 15.01.2013

Вот чистое решение GAWK:

{ # Split on double quotes to handle lines like "this, this, or this".
    printf("LINE:    '%s'\nFIELDS:", $0)
    n = split($0,q,/"/)
    f = 0
}

n == 1 { # If n is 1, there are no double quotes on the line.
    n = split($0,c,/,/)
    for (i = 1; i <= n; i++) {
        printf("  %d='%s'", i, c[i])
    }
    printf("\n")
    next
}

{ # There are "strings"; the EVEN entries in q are the quoted strings.
    for (i = 1; i <= n; i++) {
        if (0 == and(i,1)) { # i is EVEN: This is a double-quoted string.
            printf("  %d='\"%s\"'", ++f, q[i])
            continue
        }
        if (0 == length(q[i])) { # First/last field is a quoted string.
            continue
        }
        if (q[i] == ",") {
            # First/last field empty, or comma between two quoted strings.
            if (i == 1 || i == n) { # First/last field empty
                printf("  %d=''", ++f)
            }
            continue
        }
        # Remove commas before/after a quoted string then split on commas.
        sub(/^,/,"",q[i])
        sub(/,$/,"",q[i])
        m = split(q[i],cq,/,/)
        for (j = 1; j <= m; j++) {
            printf("  %d='%s'", ++f, cq[j])
        }
    }
    printf("\n")
}

С этим вводом:

This is one,23,$9.32,Another string.
Line 2,234,$88.34,Blah blah
"This is another",763,$0.00,"trouble, or not?"
"This is, perhaps, trouble too...",763,$0.00,"trouble, or not?"
2,"This is, perhaps, trouble too...",763,"trouble, or not?"
3,,"number, number","well?"
,,,
"1,one","2,two","3,three","4,four"
",commas,","no commas",",,,,,",
,"Fields 1 and 4 are empty","But 2 and 3 are not",

На выходе получается:

LINE:    'This is one,23,$9.32,Another string.'
FIELDS:  1='This is one'  2='23'  3='$9.32'  4='Another string.'
LINE:    'Line 2,234,$88.34,Blah blah'
FIELDS:  1='Line 2'  2='234'  3='$88.34'  4='Blah blah'
LINE:    '"This is another",763,$0.00,"trouble, or not?"'
FIELDS:  1='"This is another"'  2='763'  3='$0.00'  4='"trouble, or not?"'
LINE:    '"This is, perhaps, trouble too...",763,$0.00,"trouble, or not?"'
FIELDS:  1='"This is, perhaps, trouble too..."'  2='763'  3='$0.00'  4='"trouble, or not?"'
LINE:    '2,"This is, perhaps, trouble too...",763,"trouble, or not?"'
FIELDS:  1='2'  2='"This is, perhaps, trouble too..."'  3='763'  4='"trouble, or not?"'
LINE:    '3,,"number, number","well?"'
FIELDS:  1='3'  2=''  3='"number, number"'  4='"well?"'
LINE:    ',,,'
FIELDS:  1=''  2=''  3=''  4=''
LINE:    '"1,one","2,two","3,three","4,four"'
FIELDS:  1='"1,one"'  2='"2,two"'  3='"3,three"'  4='"4,four"'
LINE:    '",commas,","no commas",",,,,,",'
FIELDS:  1='",commas,"'  2='"no commas"'  3='",,,,,"'  4=''
LINE:    ',"Fields 1 and 4 are empty","But 2 and 3 are not",'
FIELDS:  1=''  2='"Fields 1 and 4 are empty"'  3='"But 2 and 3 are not"'  4=''
person ReluctantBIOSGuy    schedule 20.10.2014

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

https://en.wikipedia.org/wiki/DNF_(software)

тогда вы можете просто запустить как обычный пользователь

git clone https://git.savannah.gnu.org/git/gawk.git
cd gawk
./configure
make
sudo make install

тогда ваш вопрос о входном файле tmp.txt

this,is,a,"csv,with,embedded coma"

легко конвертируется

gawk '{patsplit("this,is,a,\"csv,with,embedded comma\"",a,"([^,]*)|(\"([^\"]|\"\")+\"[^,]*)",seps); for(i=0;i<length(a);i++) print a[i];}' tmp.txt

у вас могут возникнуть проблемы с компиляцией gawk, вам следует решить их, если они появятся.

person Chris    schedule 12.11.2019