2010-03-17 19 views
5

che sto cercando una soluzione per dividere una stringa che contiene il testo nel seguente formato:Come posso dividere una stringa per spazio bianco a meno che non sia all'interno di una singola stringa quotata?

"abcd efgh 'ijklm no pqrs' tuv" 

che produrrà i seguenti risultati:

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

In altre parole, si divide da spazi bianchi, a meno all'interno di una singola stringa quotata. Penso che potrebbe essere fatto con regex di .NET usando gli operatori "Lookaround", in particolare gli operatori di bilanciamento. Non sono così sicuro di Perl.

risposta

15

Uso 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; 

uscita:

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

Potete guardare il codice sorgente per Text::ParseWords::parse_line per vedere il modello utilizzato.

+1

Mi piace come "come faccio?" La domanda che ho sempre avuto su Perl è stata rapidamente risposta da "Usa questo modulo che fa esattamente quello che vuoi". – jergason

+0

Figure c'è un pacchetto per fare esattamente quello che mi serve. Non ero sicuro di cosa stavo cercando. Sei una rockstar, grazie! – Kivin

+5

@Jergason dà la colpa alle persone meravigliose che, quando * non * trovano esattamente ciò di cui hanno bisogno, e devono scriverle da soli, CPAN il risultato dopo. :) – hobbs

2

Quindi hai deciso di usare una regex? Ora hai due problemi.

Consentitemi di dedurre un po '. Si desidera un numero arbitrario di campi, in cui un campo è composto da testo senza contenere uno spazio, oppure è separato da spazi e inizia con una citazione e termina con una citazione (eventualmente con spazi tra parentesi).

In altre parole, si desidera eseguire ciò che fa una shell della riga di comando. Dovresti davvero riutilizzare qualcosa. In mancanza di questo, si dovrebbe catturare un campo alla volta, con un qualcosa di simile regex:

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

Dove si accoda gruppo uno alla tua lista, e continuare il ciclo con il contenuto del gruppo 2.

A il singolo passaggio attraverso una regex non sarebbe in grado di catturare un numero arbitrariamente elevato di campi. Potresti essere in grado di dividere una regex (Python lo farà, non sono sicuro di perl), ma dal momento che stai confrontando le cose al di fuori degli spazi, non sono sicuro che sia anche un'opzione.

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; 
Problemi correlati