2010-03-17 43 views
5

estoy buscando una solución a la división de una cadena que contiene texto con el siguiente formato:¿Cómo puedo dividir una cadena por espacios en blanco a menos que esté dentro de una sola cadena entre comillas?

"abcd efgh 'ijklm no pqrs' tuv" 

que producirá los siguientes resultados:

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

En otras palabras, se divide por espacios en blanco a menos dentro de una sola cadena citada. Creo que se podría hacer con expresiones regulares de .NET usando operadores "Lookaround", particularmente operadores de equilibrio. No estoy tan seguro de Perl.

Respuesta

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; 

Salida:

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

Usted puede mirar en el código fuente de Text::ParseWords::parse_line para ver el patrón utilizado.

+1

Me encanta cómo "¿cómo puedo hacer esto?" La pregunta que he tenido sobre Perl ha sido respondida rápidamente por "Use este módulo que hace exactamente lo que quiere". – jergason

+0

Cifras hay un paquete para hacer exactamente lo que necesito. No estaba seguro de lo que estaba buscando. Eres una estrella de rock, gracias! – Kivin

+5

@Jergason culpan a las personas maravillosas que, cuando * no * encuentran exactamente lo que necesitan, y tienen que escribirlo ellos mismos, CPAN el resultado después. :) – hobbs

2

¿Has decidido utilizar una expresión regular? Ahora tienes dos problemas.

Permítanme inferir un poco. Desea un número arbitrario de campos, donde un campo se compone de texto sin contener un espacio, o está separado por espacios, comienza con un presupuesto y termina con un presupuesto (posiblemente con espacios intermedios).

En otras palabras, desea hacer lo que hace un shell de línea de comando. Realmente deberías solo reutilizar algo. De no ser así, se debe capturar un campo a la vez, con una expresión regular algo así como:

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

Cuando usted adiciona un grupo a su lista, y continuar el bucle con el contenido del grupo 2.

Un el pase único a través de una expresión regular no podría capturar un número arbitrariamente grande de campos. Es posible que pueda dividir en una expresión regular (Python hará esto, no está seguro acerca de Perl), pero ya que está haciendo coincidir las cosas fuera de los espacios, no estoy seguro de que sea siquiera una opción.

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; 
Cuestiones relacionadas