Bueno, he encontrado una forma:
- Código: Seleccionar todo
1 #!/usr/bin/perl
2 use warnings;
3
4 # Entrada de prueba
5 @entrada = (
6 "depto 5 edificio A",
7 "Manzana 4 colonia 3 casa 21",
8 "depto 8 edificio 2 colonia XY",
9 );
10
11 @ordenado = qw(
12 colonia
13 manzana
14 casa
15 edificio
16 depto
17 );
18 $tam_ordenado = scalar @ordenado;
19
20 foreach $avza ( @entrada ) {
21 print "=>$avza.\n";
22 $nueva = lc($avza); # Lo pasamos a minúsculas
23
24 for ( $i = 0; $i < $tam_ordenado; $i++ ) {
25 for ( $k = $i+1; $k < $tam_ordenado; $k++ ) {
26 #print "\tBuscando $ordenado[$i]/$ordenado[$k]\n";
27 $pos1 = index($nueva, $ordenado[$i]);
28 $pos2 = index($nueva, $ordenado[$k]);
29 next if $pos1 <0 or $pos2 <0;
30 # Encontrada una pareja. Ver si está al revés
31 if ( $pos1 > $pos2 ) { # Si, hay que dar la vuelta
32 $nueva =
33 substr($nueva, 0, $pos2) .
34 substr($nueva, $pos1) . ' ' .
35 substr($nueva, $pos2, $pos1 - $pos2 - 1);
36 print "|>$nueva.\n";
37 } } }
38 print "+>$nueva.\n";
39 }
40 __END__
Salida
- Código: Seleccionar todo
=>depto 5 edificio A.
|>edificio a depto 5.
+>edificio a depto 5.
=>Manzana 4 colonia 3 casa 21.
|>colonia 3 casa 21 manzana 4.
|>colonia 3 manzana 4 casa 21.
+>colonia 3 manzana 4 casa 21.
=>depto 8 edificio 2 colonia XY.
|>depto 8 colonia xy edificio 2 .
|>colonia xy edificio 2 depto 8 .
+>colonia xy edificio 2 depto 8 .
Explicación:
* En la línea 20 hacemos un bucle por toda la @entrada
* En la línea 22, copiamos la cadena a analizar en $nueva, pasándola a minúsculas (esto es opcional, claro)
* De la 24 a 37 tenemos un doble bucle de búsqueda. Un doble bucle es necesario para contemplar el caso de que alguna de las direcciones tenga palabras 'desaparecidas' (por ejemplo, una casa dentro de una colonia)
* En las líneas 27 y 28 buscamos las dos palabras que nos interesan
* Si falta alguna de ellas, es tontería seguir, así que saltamos al siguiente (next) bucle
* Ahora, en la 31 comprobamos si están en orden inverso
* Si lo están, entonces hay que invertir su posición (32 a 35).
El proceso de 'inversión' es el siguiente:
* Hemos encontrado dos palabras, una en la posición $pos1 y otra en la $pos2
* Dividimos la cadena original ($nueva) en 3 partes:
a) La primera parte es la que va desde el comienzo hasta la primera de las palabras encontradas (sabemos que está en $pos2)
b) La segunda parte va desde $pos1 hasta el final de la cadena, más un espacio (ahora explico porqué)
c) La tercera parte es el trozo de cadena que está entre $pos2 y $pos1, menos una posición (ahora explico porqué).
El resultado es que se invierten las posiciones $pos2 y $pos1, respetando lo que ya estuviera ordenado al comienzo de la cadena.
* ¿Por qué sumamos un espacio en blanco en b)? Pues para que no quede pegado a c)
* ¿Y por qué quitamos una posición a c)? Esa posición es el espacio en blanco antes de $pos1. Si hacemos la inversión, ese espacio en blanco quedará al final, por lo que no nos sirve para nada
* De hecho... fíjate que sumamos un espacio en un sitio y se lo quitamos en otro... se podría haber recortado de otra manera para llevar esos espacios en blanco, pero hubiera quedado más complicado, con más cuentas.
Funciona, pero plantea más problemas... Antes hemos quitado las mayúsculas en la línea 22 para que pudiéramos hacer funcionar el index en 27 y 28 sin problemas, con los valores de @ordenado. Pero ¿queremos guardarlo así en la base de datos?.
Otro detalle: fíjate como respeta el caso de que existan dobles espacios en blanco entre las entradas.