PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : awk: field separator im string



moedule
25-05-2006, 15:38
hey

ich hab hier einen recht großen datensatz (190 MB) den ich gerne mit awk zerlegen möchte. das problem ist, dass der mit komma separierte datensatz einige strings enthält, die ebenfalls kommas enthalten können. diese sind mit " gekennzeichnet

wie bringe ich dem awk bei, diese kommas als field separator zu ignorieren?

danke für eure hilfe
moe

SeeksTheMoon
26-05-2006, 17:48
Wie? Ein " vor dem Komma, oder zwei drum herum oder der ganze String mit " umgeben?

moedule
26-05-2006, 18:12
drum herum, also ungefähr sowas.

126, "bla bla", 545, "hund, katze, maus", 6764, "blub"

feld1 = 126
feld2 = "bla bla"
feld3=545
feld4 = "hund, katze, maus"
feld5 = 6764
feld6="blub"

jeder string ist von zwei " eingeschlossen

awk liefert die falsche anzahl an feldern, er zählt die kommas im string mit.

hab schon versucht mit sed die kommas im string zu ersetzen, stell mich da aber zu blöd an (es werden zum beispiel auch die kommas zwischen zwei nicht zusammengehörigen " ersetzt)

moe

Romanday
26-05-2006, 22:34
hab schon versucht mit sed die kommas im string zu ersetzen, stell mich da aber zu blöd an (es werden zum beispiel auch die kommas zwischen zwei nicht zusammengehörigen " ersetzt)

moe

Alles vorher in ein Array einlesen.
mit match suchen, danach ersetzen + ausgeben.
Ist aber ein wenig hackselig.

Ich glaube du kommst mit einer anderen Scriptsprache
(Perl etc.) schneller zum Ziel.

moedule
26-05-2006, 23:45
Alles vorher in ein Array einlesen.
mit match suchen, danach ersetzen + ausgeben.
Ist aber ein wenig hackselig.

Ich glaube du kommst mit einer anderen Scriptsprache
(Perl etc.) schneller zum Ziel.

würde ich ja machen, z.B. erstmal die kommas im string ändern ... ic blicks mit den ganzen regexp nicht :-(

moe

Romanday
27-05-2006, 20:03
würde ich ja machen, z.B. erstmal die kommas im string ändern ... ic blicks mit den ganzen regexp nicht :-(

moe

1x umrühren, dann geht es:



<?function n($n){$n=str_replace(',','',$n[1]);return '"'.$n.'"';}?>
<?=preg_replace_callback('/\"([^\"]+)\"/', "n", $d)?>

moedule
29-05-2006, 02:49
danke für deine mühe!
ich hab auch ne awk-lösung:

das stichwort für google lautet: "the csv problem" und vielleicht awk. leider find ich die seite gerade nicht mehr woher ich dann die funktionierende lösung hatte ..
aber das hier sollte es irgendwie auch tun

http://groups.google.com/group/comp.lang.awk/msg/1673d9e784c68dee

moe

Romanday
29-05-2006, 20:28
danke für deine mühe!
ich hab auch ne awk-lösung:

das stichwort für google lautet: "the csv problem" und vielleicht awk. leider find ich die seite gerade nicht mehr woher ich dann die funktionierende lösung hatte ..
aber das hier sollte es irgendwie auch tun

http://groups.google.com/group/comp.lang.awk/msg/1673d9e784c68dee

moe

AWK kennt keine Callbacks und die Regex Maschine hat die neuen
Features nicht. Von daher kommst Du nur Umwege zum Ziel.
Aber wenn es unbedingt AWK sein muß -- geht auch.

moedule
29-05-2006, 20:40
nur aus gründen der vollständigkeit, ja ok es ist aufwendiger


#!/usr/bin/awk -f
BEGIN { FS=SUBSEP; OFS="|" }

{
result = setcsv($0, ",")
print

}


# setcsv(str, sep) - parse CSV (MS specification) input
# str, the string to be parsed. (Most likely $0.)
# sep, the separator between the values.
#
# After a call to setcsv the parsed fields are found in $1 to $NF.
# setcsv returns 1 on sucess and 0 on failure.
#
# By Peter Strömberg aka PEZ.
# Based on setcsv by Adrian Davis. Modified to handle a separator
# of choice and embedded newlines. The basic approach is to take the
# burden off of the regular expression matching by replacing ambigious
# characters with characters unlikely to be found in the input. For
# this the characters "\035".
#
# Note 1. Prior to calling setcsv you must set FS to a character which
# can never be found in the input. (Consider SUBSEP.)
# Note 2. If setcsv can't find the closing double quote for the string
# in str it will consume the next line of input by calling
# getline and call itself until it finds the closing double
# qoute or no more input is available (considered a failiure).
# Note 3. Only the "" representation of a literal quote is supported.
# Note 4. setcsv will probably missbehave if sep used as a regular
# expression can match anything else than a call to index()
# would match.
#
function setcsv(str, sep, i) {
gsub(/""/, "\035", str)
gsub(sep, FS, str)

while (match(str, /"[^"]*"/)) {
middle = substr(str, RSTART+1, RLENGTH-2)
gsub(FS, sep, middle)
str = sprintf("%.*s%s%s", RSTART-1, str, middle,
substr(str, RSTART+RLENGTH))
}

if (index(str, "\"")) {
return ((getline) > 0) ? setcsv(str (RT != "" ? RT : RS) $0,
sep) : !setcsv(str "\"", sep)
} else {
gsub(/\035/, "\"", str)
$0 = str

for (i = 1; i <= NF; i++)
if (match($i, /^"+$/))
$i = substr($i, 2)

$1 = $1 ""
return 1
}

}

Romanday
05-06-2006, 08:55
nur aus gründen der vollständigkeit

Mit Perl ist es noch einfacher.:D


sub g{$g=$_[0];$g=~tr/,//d;return $g;}$g=~ s/\"([^\"]+)\"/g($1)/eg;