Partiendo de una base

Usando vectores.

En realidad, sólo hemos rascado la superficie del diablo cojuelo, unas pocas líneas del principio. Pero hay que tragárselo todo, asimilarlo, sintetizarlo y volverlo a asimilar. Y para hacerlo, lo mejor es dividirlo en cachos fácilmente deglutibles, no vayamos a empacharnos. Y eso es lo que vamos a hacer con el programa siguiente, que divide la novela en cada uno de los trancos que la componen

#!/usr/bin/perl
use File::Slurp;                                                         (1)

@ARGV || die "Uso: $0 <fichero a dividir trancos>\n";                                                 (2)
my $text = read_file( $ARGV[0] ) ;                                      (1)                                      (2)
my @trancos=split("TRANCO", $text);                                                  (2)

for (@trancos[1..$#trancos]){                                                    (2)                                                    (3)
  print substr($_,0,40), "\n", "-"x40, "\n";
}
(1)
Esta vez, para variar, usamos otro módulo diferente para leer ficheros: uno que se traga el fichero sin rechistar y en una sola línea, y lo mete en una variable ($text). El módulo File::Slurp tendrás que instalarlo previamente, claro, de tu bienamada y nunca suficientemente ponderada CPAN.
(2)
Pero vamos al meollo del asunto, es decir, la matriz. Que es lo que aparece en esta línea, una matriz y como el asunto es de 11 arrobas, tiene una arroba delante. Una @, vamos. Todo lo vectorial en Perl tiene una @ delante. Los vectores/matrices[1] son variables y es aconsejable declararlos, como hacemos con @trancos; también hay vectores predefinidos, como @ARGV, que contiene los argumentos que se le pasan al programa. Precisamente en la primera de las líneas aquí referenciadas lo que se hace es comprobar si existe ese vector de argumentos. Si no hay ninguno, se sale con un mensaje de error.

El vector @trancos se define a partir del texto, partiéndolo (split) por la palabra TRANCO, que es la que hay al principio de cada capítulo de El Diablo Cojuelo.

Los elementos de un vector se pueden sacar uno por uno, como en $ARGV[0], que como es un e$calar lleva el $ delante. Los vectores empiezan por 0 y se puede trabajar con ellos elemento por elemento o a puñados, como en @trancos[1..$#trancos], que extrae del segundo elemento (que tiene índice uno) hasta el último (que no es otra cosa lo que representa $#trancos); el operador .. genera en Perl una vector que contiene una secuencia ascendente del primer elemento al último (incluidos). Es decir, 1..5 == qw( 1 2 3 4 5)

Nota

Las estructuras de datos de Perl vienen explicadas en la página de manual perldata (ya sabéis, perldoc perldata) incluyendo muy al principio los vectores.

(3)
El bucle sigue el esquema habitual (en Perl). La variable de bucle no está declarada por que es $_; dentro del bucle, mediante substr, se extraen los primeros 40 caracteres y se imprimen y luego, usando el operador x de multiplicación de cadenas ("ab"x3 dará "ababab"), se completa este bonito y útil programa.

Nota

Más información sobre los operadores de perl tecleando perldoc perlop, inclusive reglas de asociatividad y precedencia.

Pero no hemos visto cómo se asignan valores directamente a los vectores. El programa siguiente, que modifica el anterior poniendo nuestro propio ordinal a los capítulos, usa una de las formas posibles:

use File::Slurp;

my @ordinales = qw( primero segundo tercero cuarto quinto 
		    sexto séptimo octavo noveno décimo );

@ARGV || die "Uso: $0 <fichero a partir por trancos>\n";
my $text = read_file( $ARGV[0] ) ;
my @trancos=split("TRANCO", $text);

for (@trancos[1..$#trancos]){
  print shift @ordinales, "", substr($_,0,40), "\n", "-"x40, "\n";
}

El vector se declara al principio del programa, usando la forma menos incómoda, que se ahorra comillas y espacios y cosas. Siempre que cada uno de los elementos del vector sea un bloque sin espacios en medio, se puede usar qw(). La forma más general, sin embargo, sería

my @ordinales= ('Primero','Segundo',...)

Para ir recorriendo ese vector y escribiendo sus contenidos por orden, usamos shift, que extrae el primer elemento de un vector, es decir:

DB<1> @vector = qw( primero segundo tercero );

  DB<2> print shift @vector
primero
  DB<3> x @vector
0  'segundo'
1  'tercero'
. x muestra el contenido de una variable en el depurador de Perl. Por tanto, en cada iteración del bucle el vector ordinales perderá su primer elemento. Por lo demás, print escribirá todo lo que le pasemos, separado por comas. Es así de obediente.

Nota

Esta forma de recorrer un vector es más eficiente que usar un índice sobre los elementos del mismo, como suele hacerse en C. Y sólo es incomprensible si no estás acostumbrado.

Importante

Ejercicios. Una vez hechos los trancos, lo suyo sería dividir por párrafos cada uno. Y añadirle etiquetas HTML, qué diablos. Así que el ejercicio consiste en modificar el programa anterior para que divida cada tranco en párrafos y le añada etiquetas HTML, teniendo en cuenta que los párrafos comienzan (o terminan) con dos retornos de carro, pero que dependiendo del sistema operativo origen, los dos retornos de carro pueden ser \n\n o \r\n\r\n (que será el caso, si usáis el mismo fichero que yo).

Notas

[1]

Serían, en realidad, vectores o matrices unidimensionales, aunque no es difícil crear matrices multidimensionales en Perl.