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}'  

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

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 )};

-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.


2
Die Idee ist explizit, field2|field2als einzelnes Feld in der zweiten Zeile zu haben.
klimpergeist
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.