10/11/2024
En el corazón de cualquier lenguaje de programación, la manipulación de texto es una tarea fundamental. Racket, un lenguaje potente y versátil de la familia Lisp, ofrece un robusto sistema para trabajar con cadenas de caracteres, con un soporte intrínseco para Unicode que facilita el manejo de cualquier idioma y símbolo. A diferencia de otros lenguajes, las cadenas en Racket se conciben como arreglos de caracteres de longitud fija, pero con la particularidad de poder ser mutables o inmutables, una distinción crucial que afecta su comportamiento y uso.

Esta guía explora en profundidad las características, constructores, selectores y mutadores de las cadenas en Racket, así como sus operaciones de comparación, transformación y utilidades avanzadas. Entender estos conceptos es esencial para cualquier desarrollador que busque procesar o generar texto de manera eficiente y precisa en sus aplicaciones Racket.
- Fundamentos de las Cadenas en Racket
- Representación y Lectura de Cadenas
- Tabla Comparativa: Mutabilidad de Cadenas
- Preguntas Frecuentes sobre Cadenas en Racket
- ¿Cuál es la diferencia principal entre una cadena mutable e inmutable?
- ¿Cómo manejo caracteres Unicode complejos, como los diacríticos o emojis?
- ¿Qué es la normalización Unicode y por qué es importante?
- ¿Cuándo debo usar string-append versus string-join?
- ¿Cómo convierto un número a una cadena con formato específico, como añadir ceros a la izquierda o separadores de miles?
- Conclusión
Fundamentos de las Cadenas en Racket
Una cadena en Racket es, en su esencia, un arreglo de longitud fija de caracteres. Sin embargo, su diseño va más allá de esta simple definición, ofreciendo flexibilidad y control sobre su comportamiento. Las cadenas pueden ser de dos tipos:
- Mutables: Su contenido puede ser modificado después de su creación.
- Inmutables: Su contenido no puede ser cambiado una vez creadas. Si se intenta modificar una cadena inmutable con un procedimiento como
string-set!, Racket lanzará una excepciónexn:fail:contract. Las constantes de cadena generadas por el lector por defecto de Racket son inmutables.
La igualdad entre dos cadenas (equal?) se determina si tienen la misma longitud y contienen la misma secuencia de caracteres. Además, una cadena puede ser utilizada como una secuencia de valores únicos, donde cada carácter de la cadena sirve como un elemento de la secuencia, lo que permite su integración fluida con otras operaciones de secuencia en Racket.
Constructores, Selectores y Mutadores de Cadenas
Racket proporciona un conjunto completo de procedimientos para crear, acceder y modificar cadenas:
(string? v): Retorna#tsives una cadena,#fen caso contrario.(make-string k char): Crea una nueva cadena mutable de longitudk, inicializada con el carácterchar.(string char ...): Crea una nueva cadena mutable a partir de una secuencia de caracteres.(string-immutable str): Retorna una cadena inmutable con el mismo contenido questr. Sistrya es inmutable, la retorna directamente.(string-length str): Retorna la longitud de la cadenastr.(string-ref str k): Retorna el carácter en la posiciónkdestr(indexación base 0).(string-set! str k char): Cambia el carácter en la posiciónkde la cadena mutablestrachar.(substring str start [end]): Retorna una nueva cadena mutable que es una subcadena destr, desdestart(inclusive) hastaend(exclusivo).(string-copy str): Retorna una nueva cadena mutable con el mismo contenido questr.(string-copy! dest dest-start src src-start src-end): Copia caracteres desrcadest.(string-fill! s char): Rellena cada posición de la cadena mutablesconchar.(string-append str ...): Concatena las cadenas dadas en una nueva cadena mutable.(string-append* str ... strs): Similar astring-append, pero el último argumento es una lista de cadenas.(string->list str): Convierte una cadena en una lista de caracteres.(list->string lst): Convierte una lista de caracteres en una nueva cadena mutable.(build-string n proc): Crea una cadena dencaracteres aplicandoproca los enteros de 0 an-1.
Comparación y Ordenación de Cadenas
Racket ofrece funciones para comparar cadenas tanto de forma sensible como insensible a mayúsculas/minúsculas, y con o sin consideración de la localización (locale):
(string=? str ...): Retorna#tsi todas las cadenas son iguales.(string str ...): Retorna#tsi las cadenas están ordenadas lexicográficamente de forma creciente.(string<=? str ...),(string>? str ...),(string>=? str ...): Variantes para orden no decreciente, decreciente y no creciente, respectivamente.- Comparación insensible a mayúsculas/minúsculas (locale-independent):
(string-foldcase=? str ...): Compara después de plegar el caso (locale-insensitive case-folding).(string-foldcase str ...),(string-ci<=? str ...),(string-ci>? str ...),(string-ci>=? str ...): Variantes para ordenación insensible a mayúsculas/minúsculas.
- Comparación sensible a la localización (locale-dependent):
(string-locale=? str ...): Compara cadenas de forma específica para la localización actual.(string-locale str ...): Ordena cadenas de forma específica para la localización actual.(string-locale-ci=? str ...),(string-locale-ci str ...): Comparación y ordenación insensible a mayúsculas/minúsculas y sensible a la localización.
Transformación de Cadenas: Mayúsculas, Minúsculas y Normalización
El manejo de caso y la normalización Unicode son vitales para la consistencia del texto:
(string-upcase str): Convierte los caracteres destra mayúsculas usando reglas de conversión Unicode (puede cambiar la longitud de la cadena).(string-downcase str): Convierte a minúsculas.(string-titlecase str): Convierte a mayúscula la primera letra de cada secuencia de caracteres con caso.(string-foldcase str): Realiza el plegado de caso (case-folding), útil para comparaciones.- Normalización Unicode: Es fundamental para tratar con caracteres que pueden ser representados de múltiples formas (por ejemplo, 'é' puede ser un solo carácter o 'e' + acento). Racket soporta las cuatro formas de normalización Unicode: NF D (Canonical Decomposition), NF KD (Compatibility Decomposition), NF C (Canonical Composition), y NF KC (Compatibility Composition).
(string-normalize-nfd str)(string-normalize-nfkd str)(string-normalize-nfc str)(string-normalize-nfkc str)
- Conversión de caso sensible a la localización:
(string-upcase-locale str)y(string-downcase-locale str).
Manejo de Clústeres de Grafemas Unicode
Un clúster de grafemas es una unidad de texto que el usuario percibe como un solo carácter, aunque internamente pueda estar compuesto por múltiples puntos de código Unicode (por ejemplo, una letra base y un diacrítico). Racket ofrece funciones para trabajar con ellos:
(string-grapheme-span str start [end]): Retorna el número de caracteres (puntos de código) en la cadena que forman un clúster de grafemas Unicode a partir destart.(string-grapheme-count str [start end]): Retorna el número de clústeres de grafemas en una subcadena.
Funciones Utilitarias Adicionales (racket/string)
Las bibliotecas racket/string y racket extienden las capacidades de manipulación de cadenas:
(string-join strs [sep #:before-first #:before-last #:after-last]): Une una lista de cadenas, insertando un separador.(string-normalize-spaces str [sep space]): Normaliza los espacios en una cadena, recortándola y reemplazando secuencias de espacios con un único espacio.(string-replace str from to [all?]): Reemplaza todas las ocurrencias (o solo la primera siall?es#f) defromcontoenstr.(string-split str [sep #:trim? #:repeat?]): Divide una cadena en una lista de subcadenas usando un delimitador.(string-trim str [sep #:left? #:right? #:repeat?]): Recorta los caracteres de prefijo y sufijo de una cadena.(string-empty? x): Retorna#tsixes una cadena vacía.(string-contains? s contained),(string-starts-with? s prefix),(string-ends-with? s suffix): Comprueban la presencia, inicio o fin de una subcadena.(string-find s search): Retorna el índice de la primera instancia desearchens, o#fsi no se encuentra.
Conversión de Valores a Cadenas (racket/format)
La biblioteca racket/format (disponible en racket/format y racket) proporciona funciones convenientes para convertir valores de Racket a cadenas, con opciones de formato, relleno y truncamiento. Las funciones ~a, ~v, ~s y ~e son similares a format pero más concisas.
(~a v ...): Convierte valores a cadenas en mododisplayy los concatena, permitiendo control de ancho mínimo/máximo, truncamiento (#:limit-marker,#:limit-prefix?) y relleno (#:align,#:left-pad-string,#:right-pad-string).(~v v ...): Similar a~a, pero cada valor se convierte como(format "~v" v), ideal para representar valores Racket de forma legible por el programador.(~s v ...): Cada valor se convierte como(format "~s" v), útil para representaciones de cadena con escapes.(~e v ...): Cada valor se convierte como(format "~e" v), útil para representaciones "external" de valores.(~r x ...): Convierte un número racionalxa una cadena con formato altamente personalizable. Permite controlar:#:notation: 'positional o 'exponential.#:precision: Número de dígitos después del punto decimal.#:decimal-sep: Separador decimal (ej. ",").#:groupsy#:group-sep: Agrupación de dígitos en la parte entera y su separador.#:min-widthy#:pad-string: Ancho mínimo y cadena de relleno.#:sign: Cómo se indica el signo (#f,'+,'++,'parenso una lista de indicadores).#:base: Base numérica (ej. 16 para hexadecimal).#:format-exponent: Formato del exponente en notación exponencial.
Representación y Lectura de Cadenas
Cuando se imprime una cadena en Racket, se utiliza el formato de comillas dobles, donde caracteres como las comillas dobles y las barras invertidas dentro de la cadena se escapan con barras invertidas (\", \\). También se admiten escapes comunes como \n para salto de línea, \r para retorno de carro, escapes octales (\ooo) y hexadecimales (\uXXXX para Unicode). Los caracteres no imprimibles suelen mostrarse con \u cuando se imprime la cadena.

Es importante distinguir entre la impresión de una cadena como constante sintáctica y la escritura directa de sus caracteres. El procedimiento display escribe directamente los caracteres de una cadena en el puerto de salida actual, sin los escapes o comillas que se usarían para representar una constante de cadena. Por ejemplo, (display "a \"quoted\" thing") imprimirá a "quoted" thing sin las comillas externas y con las internas sin escapar.
Tabla Comparativa: Mutabilidad de Cadenas
Comprender la mutabilidad es clave para evitar errores y optimizar el rendimiento.
| Característica | Cadenas Mutables | Cadenas Inmutables |
|---|---|---|
| Definición | Su contenido puede ser modificado después de la creación. | Su contenido no puede ser modificado después de la creación. |
| Creación Típica | make-string, string, substring, string-copy, list->string. | Constantes de cadena literales (ej. "Hola"), string-immutable, string-append-immutable. |
| Modificación Directa | Sí, con string-set!, string-fill!, string-copy!. | No, lanza exn:fail:contract si se intenta. |
| Compartición Segura | Requiere precaución; modificar una copia puede afectar la original si se comparte la referencia. | Seguro para compartir; el contenido no cambiará inesperadamente. |
| Rendimiento | Más eficientes para operaciones que requieren cambios frecuentes en el lugar. | Pueden requerir la creación de nuevas cadenas para cada modificación, lo que puede ser menos eficiente para cambios iterativos. |
Preguntas Frecuentes sobre Cadenas en Racket
¿Cuál es la diferencia principal entre una cadena mutable e inmutable?
La diferencia fundamental radica en si su contenido puede ser alterado después de la creación. Una cadena mutable, como su nombre indica, puede ser modificada en el lugar utilizando funciones como string-set!. Por otro lado, una cadena inmutable no puede ser cambiada; cualquier operación que parezca modificarla en realidad retorna una nueva cadena con los cambios. Las cadenas literales (como "ejemplo") son siempre inmutables por defecto, lo que las hace seguras para compartir sin preocuparse por modificaciones inesperadas.
¿Cómo manejo caracteres Unicode complejos, como los diacríticos o emojis?
Racket maneja Unicode de forma nativa. Para caracteres complejos que pueden componerse de múltiples puntos de código (como una letra base y un acento combinado, o emojis con modificadores de tono de piel), es crucial entender los "clústeres de grafemas". Las funciones string-grapheme-span y string-grapheme-count son herramientas clave para trabajar con estos, ya que operan sobre lo que el usuario percibe como un solo carácter, en lugar de puntos de código individuales. Además, la normalización Unicode (string-normalize-nfc, etc.) es esencial para asegurar que diferentes representaciones del mismo carácter se traten de manera consistente.

¿Qué es la normalización Unicode y por qué es importante?
La normalización Unicode es un proceso que asegura que cadenas de texto que son equivalentes desde el punto de vista lingüístico o visual tengan la misma representación binaria. Es importante porque el mismo carácter o secuencia de caracteres puede ser representado de múltiples formas en Unicode. Por ejemplo, la letra 'é' puede ser un solo punto de código precompuesto o una 'e' seguida de un punto de código para el acento agudo. Sin normalización, una comparación directa de cadenas podría fallar aunque los caracteres se vean idénticos. Racket soporta las formas de normalización NFD, NFKD, NFC y NFKC para manejar estos escenarios.
¿Cuándo debo usar string-append versus string-join?
string-append se utiliza para concatenar una cantidad fija o variable de cadenas directamente, uniéndolas una tras otra sin ningún separador implícito. Es útil cuando simplemente quieres unir partes de texto. Por otro lado, string-join está diseñado específicamente para unir una lista de cadenas, e inserta un separador entre cada par de elementos. Es ideal para construir cadenas a partir de colecciones de datos, como crear una frase a partir de una lista de palabras, y ofrece opciones para separadores especiales al principio, al final o entre los últimos elementos.
¿Cómo convierto un número a una cadena con formato específico, como añadir ceros a la izquierda o separadores de miles?
Para un formateo avanzado de números, la función (~r x ...) de la biblioteca racket/format es la herramienta más potente. Permite controlar la notación (posicional/exponencial), la precisión decimal, el separador decimal, la agrupación de dígitos (separadores de miles), el ancho mínimo con relleno de caracteres específicos (como ceros a la izquierda), y cómo se muestra el signo. Esto ofrece una flexibilidad inigualable para presentar datos numéricos de forma estandarizada y legible.
Conclusión
Las cadenas en Racket son una herramienta fundamental y versátil para cualquier tarea de procesamiento de texto. Con su soporte nativo para Unicode, la distinción entre mutabilidad e inmutabilidad, y una rica colección de funciones para creación, manipulación, comparación y formateo, Racket proporciona a los desarrolladores un control excepcional sobre sus datos textuales. Dominar estas capacidades no solo mejora la robustez de las aplicaciones, sino que también facilita la creación de software que puede interactuar eficazmente con información en múltiples idiomas y formatos.
Si quieres conocer otros artículos parecidos a Cadenas (Unicode) en Racket: Una Guía Completa puedes visitar la categoría Librerías.
