2012-02-24 4 views
8

Tengo una base de datos con varios campos que contienen valores separados por comas. Necesito dividir estos campos en Perl, lo cual es bastante sencillo, excepto que algunos de los valores son seguidos por CSV anidados contenidos entre corchetes que no quiero dividir.¿Lista dividida de Perl en comas, excepto cuando está entre corchetes?

Ejemplo:

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

Lo que quiero es::

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

Puede alguno de expresiones regulares de Perl (pertos) echar una mano

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

que parte en "" me da ?

He intentado modificar una expresión regular que encontré en una situación similar SO post cuales no devolvió resultados:

#!/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

¿Qué ha intentado hasta ahora? Primero haga un esfuerzo por su cuenta y luego haga preguntas que muestren lo que ha hecho. –

+0

No puede usar una expresión regular para analizar expresiones anidadas. Necesitas un analizador completo. – Ether

+0

Puede echar un vistazo a [Text :: CSV] (http://search.cpan.org/perldoc?Text::CSV) y ver si puede ajustarlo para hacer lo que necesita. – TLP

Respuesta

9

Prueba esto:

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

Acabo de encontrar lo mismo [aquí] (http://stackoverflow.com/questions/8481345/perl-split-and-regular-expression) y funciona. ¡Gracias! – calyeung

0

¿Alguien dice que hay que hacerlo en uno ¿paso? Podría rebanar valores en un bucle. Dado tu ejemplo, podrías usar algo como esto.

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 solución que ha elegido es superior, pero a quienes digan lo contrario, las expresiones regulares tienen un elemento de recursividad que coincidirá con paréntesis anidados. El siguiente funciona bien

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; 

incluso si los paréntesis están anidados más. No, no es bonito pero funciona!

+0

+1 para solución (equilibrada). :) – zx81

0

Otro enfoque que utiliza bucles y split. No he probado el rendimiento, pero ¿no debería ser más rápido que las soluciones de expresiones regulares anticipadas (como la longitud de $str aumenta)?

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 =(); 
} 
Cuestiones relacionadas