Las cadenas de caracteres (String) son delimitadas por las comillas dobles ("
). Pueden ser de una sola línea o multi línea. En el caso de ser multi línea, estas conservarán todos los caracteres de espacio y salto de línea contenidos en el string. El caracter de comilla simple ('
) no es significativo para Wren.
Las strings pueden contener caracteres unicode en UTF-8, como también caracteres no válidos para UTF-8.
Además son inmutables. El string "porotos" no podrá ser modificado (cambiando sus caracteres) luego de su creación.
Un string puede contener los siguientes valores:
-
Una cadena de texto compuesto por una secuencia de puntos de código textuales (textual code point).
-
Una cadena iterable compuesta por una secuencia de puntos de código numérico (numeric code point).
-
Un arreglo simple de bytes indexeables.
Wren permite string multi líneas utilizando el mismo caracter de comillas dobles ("
) de las strings de una sola línea.
"
Todo esto es una string multi línea
Wren esperará hasta que aparezca
la siguiente comilla doble.
Los strings multi línea en Wren guardan tanto espacios como saltos de línea en su interior.
(no son omitidos).
"
Si utilizamos la propiedad count
podremos obtener el largo de un string.
Por ejemplo "hola".count
devolverá 4
. Hay que tener cuidado con los caracteres unicode (emojis), ya que el largo dependerá de lo que se esté contando. Wren cuenta los puntos de código (code point) unicode, por que todos los strings están bajo UTF-8 (similar al comportamiento de Ruby y Python 3).
System.print("a".count) // Retorna 1.
System.print("a".bytes.count) // Retorna 1 (Parte de la tabla ASCII original).
System.print("ñ".count) // Retorna 1.
System.print("ñ".bytes.count) // Retorna 2.
System.print("👹".count) // Retorna 1.
System.print("👹".bytes.count) // Retorna 4.
System.print("👨👩👧👦".count) // Retorna 7 al contar la unidades de código de Unicode
System.print("👨👩👧👦".bytes.count) // Retorna 25 al contar los bytes UTF-8
System.print("👨👩👧👦".count)
retorna 7 por que se está contando las unidades de código de unicode, es decir, el emoji 👨👩👧👦 está formado por los siguientes caracteres : 👨 + caracter de unión de ancho cero + 👩 + caracter de unión de ancho cero + 👧 + caracter de unión de ancho cero + 👦.
System.print("👨👩👧👦".bytes.count)
retorna 25 por que está contando los bytes necesarios para almacenar estos caracteres. bytes es una secuencia de caracteres en C, lo que permite utilizar los Strings para almacenar información en binario.
Hay dos formas de contar adicionales que Wren no soporta. La primera es contar por unidades de código UTF-16 y la otra es considerar los emojis compuestos como una unidad.
El string "👨👩👧👦" debería ser de largo 11 para la codificación UTF-16. Mientras que debería ser de largo 1 si lo consideramos como un caracter singular (lo que percibe el usuario). Según los amigos de UTF-8 Everywhere contar de estas formas es poco productivo, ya que lo que importa es realmente los code units (unidades de código) UTF-8 que se tiene al escribir un string. Por lo que Wren tiene un comportamiento adecuado. De todas formas ese tipo de conversiones y conteo podría programarse con códigos externos a Wren. Más detalles en el Glosario Unicode.
Si deseamos unir varios strings o incluir datos dentro de ellos podemos utilizar las siguientes operaciones: +
y %()
.
-
"Hola" + "Wren"
: Crea un nuevo string con la unión deHola
yWren
. EntregaráHolaWren
. Es necesario que ambos objetos sean strings. Por ejemplo si se utiliza"Hola" + 1
entregará un error similar aRuntime error: Right operand must be a string.
. Para poder unirlos tendremos que utiliza el método gettertoString
del número."Hola" + 1.toString
, retornandoHola1
.
El método toString
es parte de la clase Object
la cual es la padre de todos los tipos de datos en Wren. Tanto números, booleanos, strings y listas son objetos que heredan de esta clase.
-
"Hola %(mundo)"
: Crea un string con la fraseHola
y el contenido de la variablemundo
.
La operación %()
permite incluir cualquier instrucción Wren válida, la cual finalmente ejecutará el método toString
para ser incluido en la cadena de caracteres. Esto incluso permite tener interpolaciones anidadas, pero eso se vuelve poco legible rápidamente.
// muestra: La respuesta es 42.
System.print("La respuesta es %(20 * 2 + 2).")
// muestra: wow 149
System.print("wow %((1..3).map {|n| n * n}.join())")
También se pueden multiplicar para repetir la cadena de caracteres una cantidad de veces determinada.
// muestra hola hola hola
System.print("hola " * 3)
Si bien se pueden sumar (_+_) y multiplicar (_*_), no existe operaciones para resta (_-_) y division (_/_) dentro de una cadena de caracteres.
El String al ser una Secuencia puede utilizar sus métodos como take() que permite obtener los elementos dentro de una secuencia. El método join() es necesario para convertir nuevamente la secuencia en un String.
// muestra: hola
System.print("hola wren".take(4).join())
Los caracteres no imprimibles o Whitespace son aquellos caracteres que el computador puede ver, pero son invisibles para una persona. Los caracteres no imprimibles más comunes son el espacio (" "), la tabulación ("\t") y el salto de línea ("\n"). La combinación de dos caracteres "\t" crea un nuevo espacio tabulado, mientras que la combinación de dos caracteres "\n" crea una nueva línea dentro del String. ¡Puedes usarlos cuantás veces y dónde desees!.
Prueba el siguiente código:
System.print("Hola a todos")
System.print("\tHola a todos")
System.print("Hola\na todos")
System.print("\n\n\nHola\ta\ttodos")
Muchas veces al solicitar datos a un usuario, este puede incluir espacios adicionales al principio o final. Usualmente es buena idea eliminar estos caracteres no imprimibles antes de comenzar a procesar el dato.
var nombre = " arturo "
// Elimina solamente espacio final
System.print(nombre.trimEnd())
// Elimina solamente espacio inicial
System.print(nombre.trimStart())
// Elimina espacio inicial y final
System.print(nombre.trim())
Si se necesita ver con mayor claridad lo que sucede se puede usar el siguiente código:
var nombre = " arturo "
// Elimina solamente espacio final
System.print("-" + nombre.trimEnd() + "-")
// Elimina solamente espacio inicial
System.print("-" + nombre.trimStart() + "-")
// Elimina espacio inicial y final
System.print("-" + nombre.trim() + "-")
Muchas veces se necesitan escribir caracteres especiales en un string. Por ejemplo si quisieramos escribir "Hola Wren"
incluyendo las comillas, tendríamos que escribirlo de esta forma "\"Hola Wren\""
. Esto incluirá los caracteres de comillas dobles en la frase.
"\0" // byte NUL (Nulo) : 0.
"\"" // Comillas dobles.
"\\" // Barra invertida.
"\%" // Signo porcentaje.
"\a" // Sonido de alarma.
"\b" // Retroceso.
"\f" // Alimentación de formularios.
"\n" // Salto de línea.
"\r" // Retorno de carro.
"\t" // Tabulación.
"\v" // Tabulación vertical.
"\x48" // Byte sin codificar (hexadecimal de 2 dígitos).
"\u0041" // Code point Unicode (hexadecimal de 4 dígitos).
"\U0001F64A" // Code point Unicode (hexadecimal de 8 dígitos).
// Wren 0.4 ha introducido
"\e" // Secuencia de escape de terminal ESC.
Para indicar caracteres especiales podemos utilizar \u
(unicode para letras disponibles en los idiomas humanos), \U
(unicode para letras especiales como emoji) y \x
(bytes sin codificar).
-
System.print("\u0041\u0b83\u00DE")
= AஃÞ -
System.print("\U0001F64A\U0001F680")
= 🙊🚀 -
System.print("\x48\x69\x2e")
= Hi.
En Wren 0.4 se ha introducido un nuevo tipo de String que permite utilizar las comillas sin necesidad de escaparlas. Útil por ejemplo cuando se necesita incrustar código de otros lenguajes como HTML o JSON dentro de un script.
Los Raw Strings tienen todas las mismas características que un String normal. La única excepción es que no ejecutan interpolación ni tampoco las secuencias de escape, ya que todos los caracteres son asimilados sin procesar.
Son delimitados por tres caracteres de doble comilla ("""
). Si los delimitadores están en su propia línea los caracteres
de espaciado (\t, espacio, \n
) no serán considerados. Este delimitador no se puede escapar por lo que a penas se detecte
se considerará como terminado el Raw String.
En el siguiente ejemplo vemos un simple JSON. Donde se puede apreciar que no es necesario escapar las comillas.
"""
{
"hola": "wren",
"de" : "json"
}
"""
Podemos ver la característica de ignorar los espaciados iniciales y finales con la siguiente comparación:
// La siguiente frase tiene 8 caracteres de sangría despúes del delimitador y antes del limitador
var frase = """
Hola Wren Raw
"""
System.print("'%(frase)'") // Mostrará Hola Wren con 8 espacios de sangría
// La siguiente frase incluye 8 caracteres de espacio
frase = "
Hola Wren
"
System.print("'%(frase)'") // Muestra Hola Wren con 24 espacios de sangría
Dando el siguiente resultado (se han agregado comillas para mostrar cuando comienza y termina un resultado):
' Hola Wren Raw'
'
Hola Wren
'
Debido a que el delimitador no se puede escapar. Para incluirlo se debe utilizar la concatenación de Strings o utilizando
el método replace
.
Concatenación de String.
System.print(""" mi raw string """ + "\"\"\"")
Utilizando replace
System.print(""" mi raw string '''""".replace("'", "\""))
Ambos darán el siguiente resultado:
mi raw string """
Un String es una Secuencia de caracteres. Por lo que es posible obtener caracteres en posiciones específicas utilizando rangos (Range). El índice comieza contando desde cero para contar desde el principio de la cadena y puede tener valores negativos para contar desde el final de la cadena.
// muestra: h
System.print("hola wren"[0])
// muestra: n
System.print("hola wren"[-1])
En muchas ocasiones nos encontramos con la necesidad de eliminar la sangría que se genera al escribir código. Para esto podemos utilizar la siguientes funciones:
var contar_sangria = Fn.new {|string|
var indice = 0
var bytes = string.bytes
while(indice < bytes.count) {
var caracter = bytes[indice]
if(caracter == 0x20 || caracter == 0x09) {
indice = indice + 1
continue
}
return indice
}
return 0
}
var borrar_sangrado = Fn.new {|string|
var inicio = contar_sangria.call(string)
if(inicio == 0) return string
var lineas = string.split("\n")
lineas = lineas.map {|linea|
var izquierda = contar_sangria.call(linea)
if(izquierda >= inicio) return linea[inicio..-1]
return linea
}
return lineas.join("\n")
}
Ejemplo de uso:
// Ejemplo
var frase = """ Mucha Sangría"""
// Elimina la sangría de la frase
System.print(borrar_sangrado.call(frase))