2010-03-18 16 views
12

my $ str = "1: 2: 3: 4: 5"; mi ($ a, $ b) = división (':', $ str, 2);¿Cómo puedo dividir una cadena Perl solo en la última aparición del separador?

En el código anterior utilicé el límite como 2, por lo que $ a contendrá 1 y los elementos restantes estarán en $ b. De esta manera, quiero que el último elemento esté en una variable y que los elementos anteriores al último elemento estén en otra variable.

Ejemplo

$str = "1:2:3:4:5" ; 
# $a should have "1:2:3:4" and $b should have "5" 
$str = "2:3:4:5:3:2:5:5:3:2" 
# $a should have "2:3:4:5:3:2:5:5:3" and $b should have "2" 
+1

duplicado: http://stackoverflow.com/questions/1098295/perl-is-there-a-way-to-split-on-the-last-regex -match-only – Zaid

Respuesta

16
split(/:([^:]+)$/, $str) 
2

usted puede hacerlo usando split y revertir la siguiente manera:

my $str="1:2:3:4:5"; 
my ($a,$b)=split(':',reverse($str),2); # reverse and split. 

$a = reverse($a); # reverse each piece. 
$b = reverse($b); 

($a,$b) = ($b,$a); # swap a and b 

Ahora $a habrá 1:2:3:4 y $b habrá 5.

Una forma mucho más simple y limpia es usar expresiones regulares como Mark lo ha hecho en su respuesta.

+1

Si bien esta es una posibilidad, no es exactamente eficiente, especialmente cuando una sola línea hará el equivalente. Algo como 'my ($ a, $ b) = ($ str = ~ /(.*):(.?)/);' – Zaid

7

también se puede utilizar rindex() por ejemplo

my $str="1:2:3:4:5"; 
$i=rindex($str,":"); 
$a=substr($str,0,$i); 
$b=substr($str,$i+1); 
print "\$a:$a, \$b: $b\n"; 

salida

$ perl perl.pl 
$a:1:2:3:4, $b: 5 
+0

Dado que el separador de división es tan simple en este caso, esta es una solución más rápida que el uso una expresión regular para analizar a través de toda la expresión tratando de enlazar a '$'. – Ether

6

Puede utilizar la concordancia, en lugar de dividir:

my ($a,$b) = $str =~ /(.*):(.*)/; 
+0

Haría ese segundo '. *' A '.?', Solo para estar seguro. – Zaid

2

que sé, esta pregunta es de 4 años de edad . Pero encontré la respuesta de YOU muy interesante ya que no sabía split podría funcionar así. Así que quiero expandirlo con un extracto del perldoc split que explica este comportamiento, por el bien de los nuevos lectores. :-)

my $str = "1:2:3:4:5"; 
my ($a, $b) = split /:([^:]+)$/, $str; 
# Capturing everything after ':' that is not ':' and until the end of the string 
# Now $a = '1:2:3:4' and $b = '5'; 

De Perldoc:

Si el patrón contiene la captura de los grupos, a continuación, para cada separador, un campo adicional se produce para cada subcadena capturada por un grupo (en el orden en que el se especifican los grupos, según las referencias posteriores); si algún grupo no coincide, captura el valor undef en lugar de una subcadena. Además, tenga en cuenta que cualquier campo adicional se produce siempre que haya un separador (es decir, siempre que se produzca una división), y dicho campo adicional no cuenta para el LIMITE. (Lista de cada devueltos se proporciona en el comentario asociado) Considere las siguientes expresiones evaluadas en el contexto de la lista:

split(/-|,/, "1-10,20", 3) 
# ('1', '10', '20') 

split(/(-|,)/, "1-10,20", 3) 
# ('1', '-', '10', ',', '20') 

split(/-|(,)/, "1-10,20", 3) 
# ('1', undef, '10', ',', '20') 

split(/(-)|,/, "1-10,20", 3) 
# ('1', '-', '10', undef, '20') 

split(/(-)|(,)/, "1-10,20", 3) 
# ('1', '-', undef, '10', undef, ',', '20') 
0

Estoy un poco tarde a esta pregunta, pero que arme una solución más genérica:

# Similar to split() except pattern is applied backwards from the end of the string 
# The only exception is that the pattern must be a precompiled regex (i.e. qr/pattern/) 
# Example: 
# rsplit(qr/:/, 'John:Smith:123:ABC', 3) => ('John:Smith', '123', 'ABC') 
sub rsplit { 
    my $pattern = shift(@_); # Precompiled regex pattern (i.e. qr/pattern/) 
    my $expr = shift(@_); # String to split 
    my $limit = shift(@_); # Number of chunks to split into 

    # 1) Reverse the input string 
    # 2) split() it 
    # 3) Reverse split()'s result array element order 
    # 4) Reverse each string within the result array 
    map { scalar reverse($_) } reverse split(/$pattern/, scalar reverse($expr), $limit); 
} 

Acepta argumentos similares a split() excepto que la división se realiza en orden inverso. También acepta una cláusula de límite en caso de que necesite una cantidad específica de elementos de resultado.

Nota: esta subrutina espera un precompiled regex como primer parámetro.
Perl's split es un intérprete e interpretará /pat/ correctamente, pero intentar pasar /pat/ a una subrutina se tratará como sub($_ =~ /pat/).

¡Esta subrutina no es a prueba de balas! Funciona suficientemente bien para delimitadores simples, pero patrones más complicados pueden causar problemas. El patrón en sí no se puede revertir, solo la expresión con la que coincide.


Ejemplos:

rsplit(qr/:/, 'One:Two:Three', 2); # => ('One:Two', 'Three') 

rsplit(qr/:+/, 'One:Two::Three:::Four', 3); # => ('One:Two', 'Three', 'Four') 

# Discards leading blank elements just like split() discards trailing blanks 
rsplit(qr/:/, ':::foo:bar:baz'); # => ('foo', 'bar', 'baz') 
Cuestiones relacionadas