2012-02-24 14 views
8

Mam bazę danych z wieloma polami zawierającymi wartości rozdzielone przecinkami. Muszę podzielić te pola w Perlu, co jest dość proste, z wyjątkiem tego, że po niektórych wartościach występują zagnieżdżone pliki CSV zawarte w nawiasach, których nie chcę dzielić.Lista podzielona na Perla na przecinki, z wyjątkiem w nawiasie?

Przykład:

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

Podział na "" daje mi:

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

co chcę:

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

Czy każdy Perl regex (perts) pomagać ?

Próbowałem modyfikowanie regex ciąg znalazłem w podobny SO post która zwraca żadnych wyników:

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

Co próbowałeś do tej pory? Najpierw staraj się samodzielnie, a następnie zadawaj pytania pokazujące, co zrobiłeś. –

+0

Nie można użyć wyrażenia regularnego do analizowania zagnieżdżonych wyrażeń. Potrzebujesz pełnoprawnego parsera. – Ether

+0

Możesz rzucić okiem na [Tekst :: CSV] (http://search.cpan.org/perldoc?Text::CSV) i sprawdzić, czy możesz go ulepszyć, aby zrobić to, czego potrzebujesz. – TLP

Odpowiedz

9

Spróbuj tego:

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

Po prostu znalazłem to samo [tutaj] (http://stackoverflow.com/questions/8481345/perl-split-and-regular-expression) i to działa. Dzięki! – calyeung

0

Czy ktoś powiedzieć, trzeba to zrobić w jednym krok? Można wycinać wartości w pętli. Biorąc pod uwagę twój przykład, możesz użyć czegoś takiego.

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

wybrałeś rozwiązanie jest lepsze, ale do tych, którzy twierdzą inaczej, wyrażenia regularne mają element rekurencji który będzie pasował zagnieżdżonych nawiasów. Poniższe działa poprawnie

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; 

nawet jeśli nawiasy są zagnieżdżone dalej. Nie, to nie jest ładne, ale działa!

+0

+1 dla (zrównoważonego) rozwiązania. :) – zx81

0

Inne podejście wykorzystujące pętle i split. Nie testowałem wydajności, ale czy nie powinno to być szybsze od rozwiązań regexp z wyprzedzeniem (w miarę wzrostu długości $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 =(); 
} 
Powiązane problemy