2013-06-25 16 views
6

Mam zestaw rekord, który wygląda takWymień przecinki z rur, ale nie przecinki ujęty w cudzysłowy

"BOSW0001","Mr","Wayne","Boswell","Wayne,Jessica & Lyn","31 Baker St" 
"ELLI0007","Mrs","Bronwyn","Elliott","Bronwyn, Paul & Arianne","98A Dandaraga Rd" 
"KENN0001","Mr","Leigh","Kenning","Leigh & Beth,Cole","22 Lake St" 

Chcę zastąpić przecinek (,) z rury (|) bez wymiany przecinek wewnątrz:

"Leigh & Bethie,Coles" 
"Waynez,Jessy & Lyne" 
"Bronwynie, Paula & Arianne" 

Jak mogę to zrobić, używając wyrażenia regularnego lub innych metod?

Odpowiedz

12

Nie rób tego z wyrażeń regularnych; robisz to za pomocą odpowiedniego parsera CSV. Oto przykład (nietestowany) używający Text::CSV_XS - najlepszego w branży.

use strict; 
use warnings; 

use Text::CSV_XS; 

my $in_file = "whatever.csv"; 
my $out_file = "new.dat"; 

open my $fh, '<', $in_file or die "$in_file: $!"; 
open my $out_fh, '>', $out_file or die "$out_file: $!"; 

my $in_csv = Text::CSV_XS->new; 
my $out_csv = Text::CSV_XS->new({ sep_char => '|', eol => "\n" }); 

while(my $row = $in_csv->getline($fh)) { 
    $out_csv->print($out_fh, $row); 
} 
+3

W twoim niesprawdzonym przykładzie są 3 błędy: 1. 'readline' powinno być' getline'; 2. opcje "nowego" powinny być w haszowaniu, tzn. 'Nowym ({sep_char => '|'})'; 3. możesz potrzebować opcji 'eol' (domyślnie jest to' $ \ 'i' $ \ 'jest domyślnie undef), aby zapobiec drukowaniu wszystkich wierszy w jednym wierszu. Może możesz użyć 'new ({sep_char => '|', eol => $ /})'. – doubleDown

+1

@doubleDown dzięki - zaktualizowany. – friedo

0

Jak o wykorzystując kontekst, w którym pojawia się przecinek (między cudzysłowami):

s/","/"|"/g 
+1

Co się stanie, jeśli rekord zawiera wycinkową cytat z przecinkiem? – friedo

+0

@paddy to działa idealnie, jeśli używasz regex dzięki – Soncire

+0

Bez problemu. To nie było tak popularne (byłem zarzucany prawie tak samo jak w górę), ponieważ jest kilka nieprawdopodobnych przypadków, w których to się złamie. Ale często wiesz pewne rzeczy na temat swoich danych, a szybkie i łatwe rozwiązanie jest wystarczająco dobre. W rzeczywistości lepiej niż spędzać dużo czasu na bardziej złożonym rozwiązaniu, które może nie być konieczne. – paddy

6

Właśnie przez wzgląd na TIMTOWTDI, tutaj jest przykład z wykorzystaniem modułu podstawowego Text::ParseWords.

#!/usr/bin/env perl 

use strict; 
use warnings; 

use Text::ParseWords 'parse_line'; 

foreach my $line (<DATA>) { 
    print join '|', parse_line(',', 1, $line); 
} 

__DATA__ 
"BOSW0001","Mr","Wayne","Boswell","Wayne,Jessica & Lyn","31 Baker St" 
"ELLI0007","Mrs","Bronwyn","Elliott","Bronwyn, Paul & Arianne","98A Dandaraga Rd" 
"KENN0001","Mr","Leigh","Kenning","Leigh & Beth,Cole","22 Lake St" 
+0

dziękuję za podzielenie się mężczyzną – Soncire

+1

Nie wiem, dlaczego tak wiele osób sięgnęło po Text :: CSV, gdy ten podstawowy moduł zwykle wykonuje tę pracę równie dobrze. –

Powiązane problemy