TEMA 2.3
MÁS SOBRE LAS CADENAS DE CARACTERES





2.3.1 - ACERCA DE LAS CADENAS DE CARACTERES

En QBasic el manejo de cadenas de caracteres es extremadamente sencillo. En otros lenguajes de programación como es el caso de C las cadenas se tratan como un array de datos de tipo carácter (un tipo que no tenemos en QBasic) de longitud aproximadamente igual al número de caracteres de la cadena, y por lo tanto su longitud máxima está siempre limitada. También esta forma de trabajar implica que para hacer algo tan simple como una asignación de cadenas en esos lenguajes haya que recurrir a funciones especiales del lenguaje y no podamos usar directamente el operador de asignación, el signo igual, como si se tratara de números.

En este tema vamos a ver con detalle algunas funciones de QBasic relacionadas con cadenas que nos van a servir para manejar los datos de este tipo que nos hagan falta en nuestro programa.

Vamos a recordar un poco lo que ya sabemos de las cadenas:

Al igual que ocurre con las otras variables, no es necesario declararlas. Basta con usar un nombre de variable terminado por el carácter dólar ($). En este caso tendremos una cadena de texto de longitud variable.

En algunos casos nos puede interesar que las cadenas sean de longitud fija para ahorrar memoria (Unos 10 bytes por cadena). En este caso bastaría con declararlas usando:

DIM nombreVariable AS STRING * 25

Dónde el número que va a continuación del asterisco es la longitud máxima de la cadena. Es especialmente recomendable declarar las cadenas como de longitud fija en el caso de los arrays. Por ejemplo si hacemos:

DIM tabla (1 TO 40, 1 TO 3) AS STRING * 5

Nos estamos ahorrando unos 120 bytes en todo el array, además de que el manejo de cadenas de tamaño fijo por parte del ordenador es algo más rápido por tratarse de estructuras estáticas.

En el caso de las estructuras de datos definidas por el usuario (tipos registro) que incluyan cadenas, estas siempre tendrán que declararse con una longitud determinada.





2.3.2 - LA FUNCIÓN E INSTRUCCIÓN MID$

Una de las funciones más útiles que incluye QBasic para el manejo de cadenas de caracteres es MID$. Ya la hemos visto anteriormente en varios ejemplos, pero vamos a hacerlo ahora con más detalle. Esta es su sintaxis.

MID$("cadena", inicio, longitud)

Esta función lo que hace es extraer una porción de una cadena. Le debemos pasar tres argumentos:

Vamos con unos ejemplos:

CLS
miCadena = "Hecho en Ronda, Ciudad Soñada"
PRINT MID$(miCadena, 1, 5)
PRINT MID$(miCadena, 5, 3)
PRINT MID$(miCadena, 15, 1)
PRINT MID$(miCadena, 26, 2)
PRINT MID$(miCadena, 300, 1)
PRINT MID$(miCadena, 10, 3000)

El resultado sería:

Hecho
o e
,
ña

Ronda, Ciudad Soñada

Esta función nos puede servir para extraer un determinado carácter de una cadena. Algo que puede parecer trivial, pero que nos va a simplificar mucho determinados problemas.

Vamos con un ejemplo tonto:

CLS
miCadena = "LMXJVSD"
INPUT "Escribe un número del 1 al 7: ", num
PRINT "El"; num; "º carácter de "; miCadena; " es "; MID$(miCadena, num, 1)

Un resultado posible sería:

Escribe un número del 1 al 7: 4
El 4 º carácter de LMXJVSD es J

Muy sencillo. Sólo decir que no hemos depurado el dato de entrada y que si escribimos un cero o negativo habrá un error.

Vamos con otro ejemplo más útil que utiliza esta misma técnica para determinar la letra del DNI. Para hacer esto lo que hay que hacer es comparar el resto del número dividido entre 23 con una serie de letras ordenadas de una forma característica y dar la que corresponda.

CLS
INPUT "Escribe el número del DNI: ", dni&
PRINT "La letra es: ": MID$("TRWAGMYFPDXBNJZSQVHLCKE", (dni& MOD 23) + 1, 1)

El resultado podría ser:

Escribe el número del DNI: 74926208
La letra es: M

Podemos ver que el cálculo se hace en una sola linea de código usando la instrucción MID$.

Es importante ver que la variable dónde guardaremos el número debe ser de tipo entero largo. Si la usamos como de tipo real (sin poner el &) se redondeará y no saldrá bien el cálculo.

Con esta técnica el algoritmo ha resultado sumamente corto. A lo mejor sería más sencillo o intuitivo haberlo resuelto usando un vector de caracteres para poder acceder a sus posiciones individuales, o bien un SELECT CASE. Con cualquiera de estas soluciones el listado del programa hubiera sido mucho más largo. Tendríamos 23 posibilidades en el SELECT CASE o bien 23 asignaciones al vector.

Este problema del DNI es muy frecuente. Le falta depurar los datos de entrada y convertirlo en forma de función, para que sea mucho más portable.

Para terminar con MID$ hay que decir que además de ser una función, se puede usar también como instrucción para modificar la propia cadena.

La sintaxis sería

MID$( VariableCadena$, inicio, longitud) = Cadena$

El funcionamiento es parecido, salvo unas cuantas diferencias:

Vamos con un ejemplo:

miCadena$ = "Hecho en Ronda"
PRINT miCadena$
MID$(miCadena$, 10, 5) = "Soria"
PRINT miCadena$
MID$(miCadena$, 10, 5) = "Sevilla"
PRINT miCadena$
MID$(miCadena$, 7, 8) = "aquí"
PRINT miCadena$

El resultado sería...

Hecho en Ronda
Hecho en Soria
Hecho en Sevil
Hecho aquíevil

Hay que tener en cuenta que la longitud del tramo de cadena a reemplazar queda definido por el valor del tercer parámetro, y no por el tamaño de la expresión de cadena que asignamos. Si este es mayor se cortará, y si no llega sólo se usará lo que haya, quedando lo demás como estaba. De esta misma forma la cadena nunca aumentará o disminuirá su longitud total usando esta función. Como mucho podremos disminuir su longitud aparente usando espacios en blanco, pero realmente seguirán estando ahí formando parte de la cadena.

MID$ se usa mucho más como función que como instrucción. Hay que tener claro para que sirve cada cosa y cuando se está usando una u otra. Como función va siempre a la derecha del operador de asignación o dentro de una expresión, y como instrucción va siempre al principio de la línea de código.





2.3.3 - OTRAS FUNCIONES
DE MANEJO DE CADENAS

QBasic nos ofrece varias funciones útiles para hacer operaciones con cadenas de caracteres. Una de las más útiles es MID$ a la que hemos dedicado el apartado anterior completo. Aquí van otras:

Empecemos con dos funciones algo parecidas a MID$, pero menos avanzadas.

LEFT$("cadena", numCaracteres)
RIGTH$("cadena", numCaracteres)

La primera de ellas devuelve un determinado número de caracteres del principio de la cadena, de la izquierda, y la otra los devuelve del final, de la derecha. Siempre en el mismo orden en que están en la cadena. Se puede hacer referencia tanto a una cadena literal entre comillas o a una variable o expresión de tipo cadena. Si el número de caracteres especificado es mayor que la longitud total de la cadena se devolverá la cadena entera. Si es cero se devolverá una cadena vacía, y si es negativo habrá un error.

cadena$ = "Hecho en Ronda"
PRINT LEFT$(cadena$, 5)
PRINT RIGHT$(cadena$, 5)

Daría como resultado:

Hecho
Ronda

Ahora vamos con otras que convierten a mayúsculas y minúsculas...

UCASE$("Cadena")
LCASE$("Cadena")

UCASE$ convierte todas las letras que haya en la cadena, variable de cadena o expresión, a mayúsculas (Upper Case), y LCASE$ a minúsculas (Lower Case). Es importante tener en cuenta que no se reconocen como letras ni los acentos ni la eñe ni la u con diéresis (ü) y por lo tanto no se convierten correctamente. Vamos con un ejemplo.

cadena$ = "Una cigüeña en un balcón de África"
PRINT UCASE$(cadena$)
PRINT LCASE$(cadena$)

Daría:

UNA CIGüEñA EN UN BALCóN DE ÁFRICA
una cigüeña en un balcón de África

Ahora vamos con otras dos funciones que eliminarán los espacios en blanco que pueda haber en los extremos de una cadena.

LTRIM$("Cadena")
RTRIM$("Cadena")

LTRIM$ elimina los espacios que puede haber delante (A la izquierda, left) y RTRIM$ los que pueda haber por el final (A la derecha, right).

Esta última función es muy útil para trabajar con datos almacenados en cadenas de longitud fija (Como las que se usan en los tipos de datos definidos por el usuario para los registros). Estas cadenas siempre van rellenas con espacios hasta ocupar su longitud total, y si las manejamos con todos estos espacios pueden pasar cosas como que fallen las comparaciones o que pasen cosas imprevistas en los diseños de pantallas.

Ambas funciones pueden ser útiles para depurar datos introducidos por teclado en los que el usuario haya podido escribir espacios inútiles antes o después. Vamos con un ejemplo:

cadena$ = "          Hola!          "
PRINT "*"; LTRIM$(cadena$); "*"
PRINT "*"; RTRIM$(cadena$); "*"

Y el resultado:

*Hola!          *
*          Hola!*

En Visual Basic se dispone de una función TRIM$ que elimina los espacios tanto delante como detrás de la cadena. Aquí no la tenemos, pero su programación sería muy sencilla construyendo una nueva función a partir de estas dos.

Ahora vamos con una función que nos devuelve una cadena llena con el número de espacios que le digamos

SPACE$(num)

Puede parecer inútil, pero nos ayudará bastante en el diseño de pantallas. Por ejemplo:

PRINT "Hola"; SPACE$(40); "Que hay"

Daría:

Hola                                        Que hay

O el siguiente ejemplo más elaborado:

CLS
FOR n = 0 TO 5
	PRINT SPACE$(5 - n); "/"; SPACE$(n + n); "\"
NEXT

Dibujaría esta figura:

     /\
    /  \
   /    \
  /      \
 /        \
/          \

Vamos con otra función parecida, pero que en vez de devolver una cadena de espacios la devuelve del carácter que nosotros le digamos:

STRING(Longitud, "carácter")

o bien

STRING(Longitud, Código-ASCII)

Como se puede ver podemos especificar el carácter que queremos usando una cadena o bien usando el número de su código ASCII. Esto es especialmente útil cuando queremos dibujar un carácter que no aparece en el teclado.

Vamos con unos ejemplos:

CLS
PRINT STRING$(10, "*")
PRINT STRING$(5, 60)
PRINT STRING$(15, "RONDA")
PRINT STRING$(8, 126)

Que daría

**********
<<<<<
RRRRRRRRRRRRRRR
~~~~~~~~

Al igual que la anterior, esta función nos será muy útil para construir diseños de pantallas, pero hay que tener cuidado de no confundir su nombre STRING$ con el de tipo de datos cadena que es STRING sin el dólar detrás.

Vamos ahora con otra función que en vez de devolvernos la cadena con cierta modificación nos va a devolver un número que corresponde a la longitud (Número de caracteres) de la cadena.

LEN("cadena")

Vamos con un ejemplo que en combinación con la función STRING$ que acabamos de ver nos subraye una palabra usando guiones.

CLS
INPUT "Escribe algo: "; cad$
PRINT "              "; STRING$(LEN(cad$), "-")

Daría algo como:

Escribe algo: YA ESCRIBO ALGO
              ---------------

Esta función LEN también nos devuelve el espacio en bytes que ocupa en memoria cualquier variable. Basta con pasarle como parámetro el nombre de una variable que no sea de cadenas.

A esta categoría de funciones de manejo de cadenas habría que añadir otras que ya hemos visto como son DATE$ y TIME$, así como algunas menos utilizadas como HEX$ y OCT$ que convierten un número a sistemas de numeración en base 16 y en base 8 respectivamente, pero ya que el resultado es en forma de cadena no nos servirá para hacer ningún cálculo.

Combinando estas funciones podemos construir otras más potentes que nos hagan cosas como por ejemplo dibujar recuadros o centrar textos. Esto es lo que se verá en el tema siguiente de manejo de pantalla del texto.













CuRSo De iNTRoDuCCióN a La PRoGRaMaCióN CoN QBaSiC
© 2004 Juan M. González