2012-02-24 16 views
8

Ho un database con un numero di campi che contengono valori separati da virgola. Ho bisogno di dividere questi campi in Perl, che è abbastanza semplice tranne che alcuni dei valori sono seguiti da CSV annidati racchiusi tra parentesi che non voglio dividere.Perl split list in virgola eccetto quando tra parentesi?

Esempio:

recycling 
environmental science 
interdisciplinary (e.g. 
consumerism 
waste management 
chemistry 
toxicology 
government policy 
and ethics) 
consumer education 

Quello che voglio è::

recycling 
environmental science 
interdisciplinary (e.g., consumerism, waste management, chemistry, toxicology, government policy, and ethics) 
consumer education 

Può qualsiasi regex Perl (Perts) dare una mano

recycling, environmental science, interdisciplinary (e.g., consumerism, waste management, chemistry, toxicology, government policy, and ethics), consumer education 

Splitting su "" mi dà ?

ho cercato di modificare una stringa regex sono trovato in un simile SO post che ha prodotto alcun risultato:

#!/usr/bin/perl 

use strict; 
use warnings; 

my $s = q{recycling, environmental science, interdisciplinary (e.g., consumerism, waste management, chemistry, toxicology, government policy, and ethics), consumer education}; 

my @parts = $s =~ m{\A(\w+) ([0-9]) (\([^\(]+\)) (\w+) ([0-9]) ([0-9]{2})}; 

use Data::Dumper; 
print Dumper \@parts; 
+0

Cosa hai provato fino ad ora? Per prima cosa fai uno sforzo da solo, poi fai delle domande per mostrare quello che hai fatto. –

+0

Non è possibile utilizzare un'espressione regolare per analizzare espressioni nidificate. Hai bisogno di un parser a tutti gli effetti. – Ether

+0

Si potrebbe dare un'occhiata a [Testo :: CSV] (http://search.cpan.org/perldoc?Text::CSV) e vedere se è possibile modificarlo per fare ciò che ti serve. – TLP

risposta

9

provare questo:

my $s = q{recycling, environmental science, interdisciplinary (e.g., consumerism, waste management, chemistry, toxicology, government policy, and ethics), consumer education}; 

my @parts = split /(?![^(]+\)), /, $s; 
+0

Ho appena trovato la stessa cosa [qui] (http://stackoverflow.com/questions/8481345/perl-split-and-regular-expression) e funziona. Grazie! – calyeung

0

Qualcuno ha detto che devi farlo in un passo? È possibile suddividere una serie di valori in un ciclo. Dato il tuo esempio potresti usare qualcosa di simile.

use strict; 
use warnings; 
use 5.010; 

my $s = q{recycling, environmental science, interdisciplinary (e.g., consumerism, waste management, chemistry, toxicology, government policy, and ethics), consumer education}; 

my @parts; 
while(1){ 

     my ($elem, $rest) = $s =~ m/^((?:\w|\s)+)(?:,\s*([^\(]*.*))?$/; 
     if (not $elem) { 
       say "second approach"; 
       ($elem, $rest) = $s =~ m/^(?:((?:\w|\s)+\s*\([^\)]+\)),\s*(.*))$/; 
     } 
     $s = $rest; 
     push @parts, $elem; 
     last if not $s; 

} 

use Data::Dumper; 
print Dumper \@parts; 
2

La soluzione che avete scelto è superiore, ma a coloro che vorrebbero dire il contrario, le espressioni regolari hanno un elemento di ricorsione che corrisponderà parentesi nidificate. Il seguente funziona bene

use strict; 
use warnings; 

my $s = q{recycling, environmental science, interdisciplinary (e.g., consumerism, waste management, chemistry, toxicology, government policy, and ethics), consumer education}; 

my @parts; 

push @parts, $1 while $s =~/
((?: 
    [^(),]+ | 
    (\(
    (?: [^()]+ | (?2))* 
    \)) 
)*) 
(?: ,\s* | $) 
/xg; 


print "$_\n" for @parts; 

anche se le parentesi sono nidificate ulteriormente. No, non è carino ma funziona!

+0

+1 per soluzione (bilanciata). :) – zx81

0

Un altro approccio che utilizza i cicli e split. Non ho provato le prestazioni, ma non dovrebbe essere più veloce delle soluzioni regexp look-ahead (come aumenta la lunghezza di $str)?

my @elems = split ",", $str; 
my @answer; 
my @parens; 
while(scalar @elems) { 
    push @answer,(shift @elems) while($elems[0] !~ /\(/); 
    push @parens, (shift @elems) while($elems[0] !~ /\)/); 
    push @answer, join ",", (@parens, shift @elems); 
    @parens =(); 
} 
Problemi correlati