2010-03-17 15 views
5

szukam rozwiązania podziału ciąg, który zawiera tekst w następującym formacie:Jak mogę podzielić ciąg przez białe znaki, chyba że wewnątrz jednego cudzysłowu ciąg znaków?

"abcd efgh 'ijklm no pqrs' tuv" 

który przyniesie następujące wyniki:

['abcd', 'efgh', 'ijklm no pqrs', 'tuv'] 

Innymi słowy, to dzieli spacjami chyba wewnątrz pojedynczego cudzysłowu. Myślę, że można to zrobić za pomocą wyrażeń regularnych .NET przy użyciu operatorów "Lookaround", szczególnie operatorów równoważących. Nie jestem pewien co do Perla.

Odpowiedz

15

Zastosowanie Text::ParseWords:

#!/usr/bin/perl 

use strict; use warnings; 
use Text::ParseWords; 

my @words = parse_line('\s+', 0, "abcd efgh 'ijklm no pqrs' tuv"); 

use Data::Dumper; 
print Dumper \@words; 

wyjściowa:

C:\Temp> ff 
$VAR1 = [ 
      'abcd', 
      'efgh', 
      'ijklm no pqrs', 
      'tuv' 
     ];

Możesz zajrzeć na kodzie źródłowym Text::ParseWords::parse_line aby zobaczyć wzór używany.

+1

Uwielbiam, jak "jak to zrobić?" Pytanie, jakie kiedykolwiek miałem na temat Perla, szybko zostało odebrane przez "Użyj tego modułu, który robi dokładnie to, co chcesz". – jergason

+0

Liczby jest pakiet do zrobienia dokładnie to, czego potrzebuję. Nie byłem pewien, czego szukałem. Jesteś gwiazdą rocka, dzięki! – Kivin

+5

@Jergason obwiniam to o wspaniałych ludzi, którzy, gdy * nie * znajdują dokładnie to, czego potrzebują, i muszą napisać to sami, CPAN to wynik później. :) – hobbs

2

Więc zdecydowałeś się użyć wyrażenia regularnego? Teraz masz dwa problemy.

Pozwolę sobie trochę wywnioskować. Chcesz dowolną liczbę pól, gdzie pole składa się z tekstu bez zawierającego spacji lub jest oddzielone spacjami i zaczyna się od cudzysłowu, a kończy się cytatem (prawdopodobnie ze spacjami między nimi).

Innymi słowy, chcesz zrobić to, co robi powłoka wiersza poleceń. Naprawdę powinieneś po prostu ponownie użyć czegoś. Jeżeli to niemożliwe, należy uchwycić pola na raz, z regex coś takiego:

^ *([^ ]+|'[^']*')(.*) 

Gdzie dołączeniu jednej grupy do swojej listy i kontynuować pętlę z treścią grupy 2.

A pojedyncze przejście przez wyrażenie regularne nie może uchwycić arbitralnie dużej liczby pól. Możesz być w stanie podzielić na regex (pyton to zrobi, nie wiesz o perlu), ale ponieważ dopasowujesz elementy poza polami, nie jestem pewien, czy to nawet opcja.

3
use strict; use warnings; 

my $text = "abcd efgh 'ijklm no pqrs' tuv 'xwyz 1234 9999' 'blah'"; 
my @out; 

my @parts = split /'/, $text; 

for (my $i = 1; $i < $#parts; $i += 2) { 
    push @out, split(/\s+/, $parts[$i - 1]), $parts[$i]; 
} 

push @out, $parts[-1]; 

use Data::Dumper; 
print Dumper \@out; 
Powiązane problemy