awk, wenn sowohl Trennzeichen als auch Anführungszeichen für ein Feld verwendet werden

7

Ich habe eine Datei im folgenden Format:

field1|field2|field3
field1|"field2|field2"|field3

Beachten Sie, dass die zweite Zeile doppelte Anführungszeichen enthält. Die Zeichenfolge in doppelten Anführungszeichen gehört zu Feld 2. Wie wird dies mit awk extrahiert? Ich habe ohne Ergebnisse gegoogelt. Ich habe es auch ohne Glück versucht

FS='"| "|^"|"$' '{print $2}'  
user2773013
quelle
stackoverflow.com/questions/7804673/…
Ciro Santilli 5 病毒 病毒 审查. 法轮功 5.

Antworten:

10

Wenn Sie eine aktuelle Version von haben, haben gawkSie Glück. Es gibt die hierFPAT dokumentierte Funktion

awk 'BEGIN {
 FPAT = "([^|]+)|(\"[^\"]+\")"
}
{
 print "NF = ", NF
 for (i = 1; i <= NF; i++) {
    sub(/"$/, "", $i); sub(/^"/, "", $i);printf("$%d = %s\n", i, $i)
 }
}' file

NF =  3
$1 = field1
$2 = field2
$3 = field3
NF =  3
$1 = field1
$2 = field2|field2
$3 = field3
iruvar
quelle
Sie können + durch * ersetzen FPAT = "([^|]*)|(\"[^\"]+\")", um leere Felder zu behandeln, wie||
Reza Sanaie
Brillant. Wenn ich dies jedoch für durch Kommas getrennte Dateien verwende, werden doppelte Anführungszeichen im Feld nicht berücksichtigt, daher verwende ich FPAT = "([^,]*)|(\"([^\"]|\"\")*\")". Für das obige mit Rohrbegrenzer wäre es FPAT = "([^|]*)|(\"([^\"]|\"\")*\")".
Reg Whitton
Was ist, wenn ich kein FPAT zur Verfügung habe?
musicin3d
@ musicin3d, in diesem Fall werfen Sie einen Blick auf Sobriques Perl-Lösung
iruvar
1

Dies ist etwas, in das Sie einsteigen csv- wenn das Trennzeichen Teil des Feldes ist, wird es in Anführungszeichen gesetzt. Das macht es plötzlich VIEL schwieriger, es zu analysieren, weil man sich nicht einfach auf ein Delim aufteilen kann.

Glücklicherweise haben Sie, wenn dies perleine Option ist, das Text::CSVModul, das diesen Fall behandelt:

#!/usr/bin/env perl
use strict;
use warnings;

use Text::CSV;

my $csv = Text::CSV -> new ( { 'sep_char' => '|' } );

while ( my $row =  $csv -> getline ( *STDIN ) ) {
   print $row -> [1],"\n";
}

Könnte dies wahrscheinlich zu einem Inline / Pipeable verdichten, wenn Sie es vorziehen - so etwas wie:

perl -MText::CSV -e 'print map { $_ -> [1] ."\n" } @{ Text::CSV -> new ( { 'sep_char' => '|' } ) -> getline_all ( *ARGV )};
Sobrique
quelle
-2

Möglicherweise möchten Sie diese Daten sedso formatieren, dass sie leichter analysiert werden awkkönnen. zum Beispiel:

$ sed 's/"//g' awktest1.txt 
field1|field2|field3
field1|field2|field2|field3

$ sed 's/"//g' awktest1.txt > awktest2.txt

$ awk 'BEGIN {FS = "|"} ; {print $2}' awktest2.txt 
field2
field2

Andererseits kenne ich die Art der Daten, mit denen Sie arbeiten, nicht.

Timothy Pulliam
quelle
2
Die Idee ist explizit, field2|field2als einzelnes Feld in der zweiten Zeile zu haben.
klimpergeist