Tiszteletem az uraknak,
egy szöveges csv állományban ahol a mezők opcionálisan idézőjelek között vannak (") néha egy szöveges mezőben is előfordulás az idézőjel.
Nem kell mondanom ezzel az egész feldolgozást padlóra küldve.
Íme egy példa ahol a 4. mezőben a "C" rész a hunyó:
"AAA";"BBBB";"D";"COFFEE "C" FUT.";1.;"USD";.00000000000;"USD";"7000";""
Egy lehetséges megoldás hogy lecserélem a problémás helyen (és csak ott) a `"` jelet pl -> `'`-re.
Pontosabban ahol nem `;"` így vagy `";` így jelentkezik plusz a sor vége és eleje (ahol úgy csak `"` önmagába fordul elö) kivétel a többi helyen cserélendő.
Na ezt meg lehet egy egy soros sed-del csinálni?
Köszönöm a tippeket előre is.
Üdv
MZ.
- 1856 megtekintés
Hozzászólások
Szervusz !
- a legjobb dolog az, ha a kiindulási konvertálást tudod irányítani
- ebben a helyzetben egy szövegszerkesztő csere funkcióját hívnám segítségül: ";" csere ;" csere, "; csere.
(De SED-re is írhatsz scriptet a fenti hármas szabályt figyelembe véve.
saját magam tabulátoros mezőelválasztást használok; a más mezőszeparátor TAB-ra változtatására írtam (linux alatt) egy primitív C programocskát.
CSZ
- A hozzászóláshoz be kell jelentkezni
Szervusz CSZ!
Csak script megoldás jöhet szóba mert az egész egy bath-feldolgozás része.
- A hozzászóláshoz be kell jelentkezni
inkabb ilyesmit kellene csinalni, hogy:
awk 'BEGIN { FS=";"; } { ... }'
szoval hogy az awk-ban a field szepara'tor (FS) legyen a pontosvesszo", igy ott vagja szet a sorokban a mezoket ahol szeretnenk, mindegyik mezo"t lekezeled ugy ahogy tudod/akarod/kell, es akkor jo lesz.
szoval awk, inkabb, azt pont erre talaltak ki lenyegeben. sed-ben is biztos meg lehet csinalni, de igy joval egyszerubb.
pontosan egyebkent nem ertem mit takar(hat) ez a "feldolgozas", igy ennel konkretabbat nem nagyon tudok irni...
- A hozzászóláshoz be kell jelentkezni
Ha jobb nem lesz:
sed -e "s/\"\([[:alnum:][:space:]]*\)\"\([[:alnum:]]*\)\"/\"\1'\2'/g" minta.txt
Kieg.: Ha biztosan nem lehet az érintett helyen szám, akkor az "alnum" helyett "alpha" is elég.
2. kieg. Ha biztosan ilyen alakú: 'szóköz"betűk"szóköz', akkor:
sed -e "s/\([[:space:]]\)\"\([[:alpha:]]*\)\"\([[:space:]]\)\(\)/\1'\2'\3/g" minta.txt
-----
"Én vagyok a hülye, hogy leállok magával vitatkozni."
- A hozzászóláshoz be kell jelentkezni
egynelöre nincs jobb.
Ugy látszik én bonyolitottam tul a dolgot.
Én ugy képzeltem hogy ki kell zárni a sor eleji (^) és végi($) sima idézöjelekt és utánn kell keresni a kivételekt.
Ha jól értem te egyszerüen a xxx"xxx"xxx mintát (amibe nincs ;)keresed és cseréled.
Csak egy dolog ne világos a szintaxisban, az uj mintadefinicio :\1'\2'\3
A számok mit jelentenek?
Köszi mégegyszer.
- A hozzászóláshoz be kell jelentkezni
A zárójelek közötti stringeket rendre a \1, \2 és a \3 jelöli. Tehát a \1 az első zárójelpár közzé zárt sztring, a \2 a második zárójelpár közzé zárt sztring, ... Pontosabban az adott mintára illeszkedő találatot jelenti.
-----
"Én vagyok a hülye, hogy leállok magával vitatkozni."
- A hozzászóláshoz be kell jelentkezni
köszönöm, megint tanúltam valamit :-)
- A hozzászóláshoz be kell jelentkezni
Ez viszont beégetve használja ugyan a separátor ";"-ket, de elvileg jól cserelé a hibás (páratlan) "-ket mezőn belől (mármint a mező végén lezárja és + '-t illeszt be.):
sed -e "s/;\"\([^;\"]\+\)\"\([^\";]\+\)\"\?\([^\";]*\"\);/;\"\1'\2'\3\;/g"
Csak mert sed-hez is kedvem volt, nem csak AWK-hoz :-)
- A hozzászóláshoz be kell jelentkezni
Sed-del szerintem nem (iiletve csak csúnya regexppel :-D), de awk-val szebb:
awk 'BEGIN {FS=";"} { for (i=1; i<=NF; i++) { printf("%s;",gensub("^(\"[^\"]+)\"([^\"]+)\"([^\"]+\")$","\\1'"'"'\\2'"'"'\\3","",$i))}printf("\n","") }'
A kedvencem az ' escapelése ;-)
- A hozzászóláshoz be kell jelentkezni
bzsoltika, köszönöm ez is tökéletes megoldás.
Csak egy apróság szól (egyenlöre) a sed mellett: gyorsabb.
5,4 millio sort kell atfésülni és ott sed kicsit jobban teljesít.
- A hozzászóláshoz be kell jelentkezni
Azzal az energiaval amit az egy sorba paszirozasra (es annak bugfixelesere) forditasz, lehetne egy rovidke amde korrekt parsert irni ra barmelyik scriptnyelven. :-/
- A hozzászóláshoz be kell jelentkezni
Ezt is belátom, de a környezet adott és nincs mindenféle scritnyelv installálva (még perl sem).
Volt egy konkrét parser javában irva, az kb. 4 órát molyolt rajta, de mivle kétoránkét jönnek az uj adatok ez a megoldás nem volt járható.
Mivel van egy shell szürö most elétéve, kézenfekvö hogy a hibás sorokat is igy gyomláljam ki.
- A hozzászóláshoz be kell jelentkezni
Ez így hibás CSV, ha " szerepel az adatban, akkor azt duplázni kell. Ha tudod módosítani a CSV generálást, akkor érdemes ezt berakni, és nem fog borulni a feldolgozás.
pl:
"123";"monitor 20"" tft";";ez adat!;"
Ha nem, akkor maradnak azok a megoldások, amit a kollégák írtak.
- A hozzászóláshoz be kell jelentkezni
http://search.cpan.org/~makamaka/Text-CSV-1.21/lib/Text/CSV.pm
"In case there is really bad CSV data, [...] there is a way to get that parsed, and leave the quotes inside the quoted field as-is. This can be achieved by setting allow_loose_quotes AND making sure that the escape_char is not equal to quote_char."
#!perl
use 5.010;
use strict;
use warnings;
use Text::CSV;
use Data::Dumper;
my $csv = Text::CSV->new(
{ sep_char => ';',
allow_loose_quotes => 1,
escape_char => '\\',
}
);
my $status = $csv->parse(
'"AAA";"BBBB";"D";"COFFEE "C" FUT.";1.;"USD";.00000000000;"USD";"7000";""');
my @columns = $csv->fields;
warn Dumper( $status, \@columns );
Output:
$VAR1 = 1;
$VAR2 = [
'AAA',
'BBBB',
'D',
'COFFEE "C" FUT.',
'1.',
'USD',
'.00000000000',
'USD',
'7000',
''
];
- A hozzászóláshoz be kell jelentkezni
vagy:
#!/usr/bin/python
import sys
f = open(sys.argv[2],'w')
for line in open(sys.argv[1]).readlines():
f.write(";".join([x.lstrip('"').rstrip('"').replace('"','\'') for x in line.split(';')]))
- A hozzászóláshoz be kell jelentkezni