Cadenas y colecciones
Genie ofrece varias maneras de operar con las cadenas de texto.
También ofrece la posibilidad de agrupar datos del mismo tipo (cadenas, números y cualquier tipo de dato) en una secuencia ordenada llamada array.
Además, Genie tiene otros formatos de datos más sofisticados, a modo de colecciones de elementos, que incluyen las listas y los diccionarios.
Tabla de Contenidos
Cadenas
En Tipo de datos ya vimos que las cadenas de texto son un tipo de datos que se definen con :string.
Unir cadenas
Sabemos que podemos unir dos cadenas simplemente usando el símbolo “+”.
init a: string = "Hola" b: string = "Adiós" c: string = "Pepe" saludo: string = a + " " + c print saludo despedida: string = b + " " + c stdout.printf (despedida)
Otra forma de unir cadenas es utilizando el método concat.
init a:string = "Hola" b:string = "Pepe" saludo:string = "" print saludo.concat (a, " ", b)
Conocer longitud
Podemos saber la longitud de una cadena (¡ojo!, los espacios en blanco también cuentan).
init a:string = "Genie es mi lenguaje." print ("La frase tiene %d elementos", a.length)
Esto devuelve:
La frase tiene 21 elementos
Chequear contenido
Podemos determinar si una cadena contiene otra, por ejemplo:
init contactos:string = "Alicia Pepe Antonio Juan" if ("Juan" in contactos) print "Tengo a Juan en mi agenda" else print "No puedo llamarlo."
Y también con contains:
init contactos:string = "Alicia Pepe Antonio Juan" if contactos.contains ("Pepe") print "Tengo a Pepe en la agenda."
Índices
De una cadena podemos extraer cualquier carácter utilizando los corchetes y la posición que ocupa ese carácter en la cadena (otro ¡ojo!, se empieza a contar desde 0).
init a:string = "Genie es mi lenguaje." print ("El cuarto caracter es %c", a[3]) print ("El primer caracter es %c", a[0])
Este código devuelve:
El cuarto caracter es i El primer caracter es G
init a:string = "Genie es mi lenguaje." print ("%s me encanta.", a[0:5])
Genie me encanta.
También podemos extraer el índice que ocupa un carácter:
init a:string = "Genie es mi lenguaje" indice:int = a.index_of("G") print "%d", indice
Extraer y sustituir
Para sustituir una subcadena por otra con replace:
init a:string = "Genie es mi lenguaje" print (a.replace("Genie","Python"))
También podemos extraer y sustituir subcadenas con slice y splice:
init a:string = "Genie es mi lenguaje" // extrae una parte extrae:string = a.slice(0, 5) print extrae // extrae y sustituye sustituye:string = a.splice(0, 5, "Python") print sustituye
Y con los índices que vimos antes:
init a:string = "Genie Python" b:string = "es mi lenguaje" c:string = a[0:6] // Tomamos también el espacio en blanco print c + b
Eso mismo lo podemos hacer con el método substring:
init a:string = "Genie Python" extracto:string = a.substring (0, 5) print extracto
Dividir y unir
También podemos separar una cadena dados ciertos separadores, y unir ciertos elementos en una cadena nueva.
init s:string = "Utilizando separadores para dividir cadenas" for s2 in s.split(" ") print(s2) x:string = "Separa-esta-cadena-por-los-guiones" for x2 in x.split("-") print x2
Como vemos, la separación con split nos permite iterar sobre una cadena. Y esto es así porque realmente la función split devuelve una matriz (array) de cadenas.
Y a la inversa, teniendo otro array de cadenas, podemos unir sus elementos en un nuevo string con joinv.
init colores:array of string = {"rojo", "verde", "azul"} // Unimos los strings de este array // con distintos elementos (o con ninguno) m:string = string.joinv(":", colores) print m n:string = string.joinv(" ", colores) print n o:string = string.joinv("", colores) print o
rojo:verde:azul rojo verde azul rojoverdeazul
Otros métodos
init texto:string = "Bienvenido a Genie Doc." // texto a mayúsculas mayus:string = texto.up() print mayus // texto a minúsculas minus:string = texto.down() print minus // texto al revés reves:string = texto.reverse() print reves
El constructor de cadenas
Para finalizar por ahora con las cadenas, también comentar que existe un 'constructor de cadenas' (StringBuilder) que admite varios métodos para operar con ellas.
init paleta_colores:array of string = {"azul", "blanco", "rojo", "verde"} var paleta_nueva = new StringBuilder () // creamos el constructor for color in paleta_colores paleta_nueva.append (color + " ") // agregamos nuevas cadenas al constructor stdout.printf ("La nueva paleta de colores tiene %s\n", paleta_nueva.str) paleta_nueva.prepend ("negro ") // agrega al inicio del constructor stdout.printf ("La nueva paleta de colores tiene %s\n", paleta_nueva.str) paleta_nueva.insert (6, "morado ");//inserta cadena en una posición determinada stdout.printf ("La nueva paleta de colores tiene %s\n", paleta_nueva.str) print "%lu", paleta_nueva.len // devuelve el número de caracteres // extrae uno o varios caracteres del constructor stdout.printf ("El primer caracter es %c\n", paleta_nueva.str[0]) stdout.printf ("El primer color es %s\n", paleta_nueva.str[0:5])
Caracteres Unicode y ASCII
init a:string = "Geníe es mi lenguaje." print ("El cuarto caracter es %c", a[3])
En uno de los códigos anteriores hemos acentuado la letra i de Genie ¿qué pasará?
La compilación es correcta pero la ejecución nos devuelve:
[Invalid UTF-8] El cuarto caracter es \xc3
Esto pasa porque intenta devolvernos un carácter que está fuera de ASCII (como acentos, ñ, diéresis…).
Una manera que tiene Genie de manejar caracteres Unicode que están fuera del rango ASCII:
init Intl.setlocale( LocaleCategory.ALL, "" ) a:string = "¿Sabías que mañana es mi cumpleaños?" print a
Anteriormente ya hemos visto otra manera de imprimir este tipo de caracteres:
init a:string = "¿Sabías que mañana es mi cumpleaños?" stdout.printf (a)
Pero esto no resuelve el problema de extraer e imprimir el carácter 'í' de Geníe. Vamos a probar una solución sencilla.
Sabiendo que con los corchetes no solo podemos conseguir un carácter, también una subcadena poniendo dentro el primer elemento a obtener, seguido de dos puntos y el primer elemento no extraído. Por ejemplo:
init a:string = "Genie es mi lenguaje." print ("%s me encanta.", a[0:5])
Genie me encanta.
Sabiendo eso, llegamos fácilmente a la solución:
init a:string = "Geníe es mi lenguaje." stdout.printf ("El cuarto caracter es %s", a[3:5])
Eso nos facilita mucho las cosas porque así extraemos un string (no un carácter), y eso sabemos imprirmirlo aunque no sea ASCII.
Aunque ahora nos ha resuelto el problema, esta solución no deja de ser simple. Con una función y algún bucle condicional podríamos llegar a otras soluciones más complejas.
Otra consecuencia de los dichosos caracteres ASCII:
init a:string = "Río" print ("La cadena tiene %d elementos", a.length) b:string = "Caña" print ("La cadena tiene %d elementos", b.length)
La cadena tiene 4 elementos La cadena tiene 5 elementos
Esto es así porque tanto 'í' como 'ñ' ocupan 2 espacios cada una. Es importante tenerlo en cuenta. Una solución es contar caracteres y no espacios ocupados (en í, i ocupa un espacio y el acento ocupa otro):
init a:string = "Río" print ("La cadena tiene %d elementos", a.char_count())
La cadena tiene 3 elementos
Arrays
Acabamos de ver algunos ejemplos de arrays. Un array o matriz es una colección ordenada de elementos de un tipo de dato con un valor determinado.
Un array se crea mediante 'array of tipo_de_datos'. Por ejemplo, array of string o array of int seguido del tamaño fijo del array.
Podemos crear matrices de tamaño fijo indicando su tamaño entre corchetes. Así, para crear un array de 10 enteros:
var a = new array of int[10]
Se puede acceder a un elemento individual de un array a través de su índice de posición. Y podemos obtener la longitud de un array mediante nombre_array.length.
init var letras = new array of string[3] letras[0] = "abc" letras[1] = "def" letras[2] = "xyz" print(letras[0]) print "%d", letras.length
Los arrays también pueden inicializarse directamente, y en ese caso caso no hay necesidad de especificar una longitud determinada (y en ese caso, se puede redefinir su tamaño y añadir nuevos elementos).
También se puede iterar sobre los elementos de una array con la instrucción for…in.
En el siguiente código se muestran ejemplos de las posibilidades de los arrays:
init paleta_colores:array of string = {"azul", "blanco", "rojo", "verde"} print "Una paleta con %d colores.", paleta_colores.length // 4 print "Paleta de colores:" for color in paleta_colores // recorre los elementos del array print color print "Cambio color:" paleta_colores[1] = "negro" // cambia el valor de un elemento for color in paleta_colores print color var paleta_nueva = new array of string[3] // array de 3 elementos var i = 0 for color in paleta_colores paleta_nueva[i] = color // incorpora valores del otro array (solo 3) i++ print "Nueva paleta:" for color in paleta_nueva print color lista_numeros:array of int = {1, 2, 3, 4, 5} stdout.printf ("Una lista de %d números: ", lista_numeros.length) // 5 for n in lista_numeros stdout.printf ("%d ", n)
Usando los índices de posición de un array, podemos dividirlo con [inicio:fin] (el resultado de dividir una matriz no es una copia de los datos, es una referencia a éstos).
init a: array of int = { 2, 4, 6, 8 } b: array of int = a[1:3] print("%d", b.length) // 2 print("%d", b[0]) // 4 print("%d", b[1]) // 6
Se pueden añadir elementos a una matriz dinámicamente haciendo uso del operador += (esto sólo funciona para las matrices definidas localmente o privadas):
init e: array of int = {1, 2, 3, 4} e += 5 e += 6 e += 7 print("%d", e.length) // 7 print ("%d", e[4]) // 5
El tamaño de una matriz se puede variar llamando a resize():
init a: array of int = {1, 2, 3, 4} print("%d", a.length) // 4 a.resize(6) print("%d", a.length) // 6 print ("%d", a[4]) // 0
Los arrays pueden contener cualquier tipo de datos, incluso estructuras, y datos anidados o multidimensionales (array de arrays). Estas matrices apiladas, compuestas o matrices de matrices se definen con [,] o con [,,].
En estos casos, hay que tener en cuenta que cada elemento tiene que tener la misma longitud, y que length almacena la longitud de cada dimensión pero no de la matriz global. Además, a partir de una matriz multidimensional no se puede obtener una matriz de una dimensión, ni siquiera dividir una matriz multidimensional.
init var a = new array of int[3, 4] // a : array of int[,] también válido a = { {2, 4, 6, 8}, {3, 5, 7, 9}, {1, 3, 5, 7}} print("%d", a.length[1]) // 4
Listas
Este tipo de datos avanzados (Gee collection datatypes), listas y diccionarios, no se admiten en las bibliotecas C estándar por lo que se requiere una biblioteca adicional denominada libgee.
Se trata de una pequeña biblioteca (libgee-0.8-2 y libgee-0.8-dev) que debe instalarse en el sistema y que también se lo tendrá que instalar cualquier persona que quiera ejecutar un programa así compilado.
Además, se debe indicar explícitamente al compilador Vala que lo vincule en la línea de comandos, por ejemplo:
$valac --pkg gee-0.8 test.gs
Cuando no se hace uso de listas o diccionarios, como hasta ahora en esta Wiki, entonces no necesita esta biblioteca.
Las listas son colecciones ordenadas de elementos, accesibles por índice numérico. Pueden crecer y reducirse automáticamente a medida que se añaden o eliminan los elementos. En esencia una lista es un array dinámico (y más potente).
Se crea una nueva lista con la misma sintaxis que otros elementos genéricos:
var mi_lista = new list of string
El código anterior crea una lista de cadenas pero también la podemos crear con otro tipo de datos.
Podemos acceder (por posición y por valor) y cambiar los elementos de una lista igual que hemos hecho con los arrays. E igualmente son iterables con for…in.
Pero además las listas disponen de varios métodos para operar con sus elementos:
- add
- clear
- contains
- get
- index_of
- insert
- set
- remove
- remove_at
// compilar con valac --pkg gee-0.8 nombre_archivo.gs init var invitados = new list of string // Añadimos elementos al final invitados.add("Pepe") invitados.add("Juan") invitados.add("Alicia") // Confirmamos elementos de la lista if invitados.contains("Antonio") == false print "Antonio no esta invitado." if invitados.contains("Juan") == true print "Adelante, Juan." // Rescatamos el valor de la posición 1 y luego le cambiamos el valor print "Invitado numero 1: %s", invitados.get(1) invitados.set(1,"Pablo") print "Invitado numero 1: %s", invitados[1] // Añadimos elementos en posiciones invitados.insert(1,"Antonio") invitados.insert(1,"Manuel") // Bucle para recorrer la lista for persona in invitados print persona // Borramos elementos por posición y por valor invitados.remove_at(4) invitados.remove("Antonio") // Obtenemos la posición de un elemento por su valor print "Posicion de Pablo en la lista: %d", invitados.index_of("Pablo") // asignamos a la posición 2 el valor Enrique invitados.set(2,"Enrique") for persona in invitados print persona
Para crear listas más complejas que contengan datos de distinto tipo podemos crear un objeto y después crear una lista de ese objeto. Aunque en esta Wiki todavía no hemos visto algunos de esos recursos, dejo un ejemplo que puede ayudar a hacernos una idea:
// compilar con valac --pkg gee-0.8 nombre_archivo.gs // creamos la clase Agenda (un objeto) class Agenda: Object nombre:string apellido:string fijo:int movil:int contacto:Agenda init // creamos una lista de la clase Agenda var lista_contactos = new list of Agenda // Instanciamos la clase Agenda contacto = new Agenda() // Introducimos datos contacto.nombre = "Pepe" contacto.apellido = "Viyuela" contacto.fijo = 913234234 contacto.movil = 654123876 // Añadimos los datos a la lista lista_contactos.add(contacto) // Repetimos con otro contacto: // primero debemos instanciar nuevamente Agenda // lo podemos hacer con el mismo nombre // después introducimos más datos // y añadimos a la lista de contactos contacto = new Agenda() contacto.nombre = "Ana" contacto.apellido = "Villanueva" contacto.fijo = 965765123 contacto.movil = 654876876 lista_contactos.add(contacto) // Recorremos la lista de contactos (lista del objeto Agenda) for var x in lista_contactos print x.nombre + " " + x.apellido + " - " + x.fijo.to_string() + " - " + x.movil.to_string()
Este ejemplo se puede hacer más complejo anidando objetos en objetos y todos ellos añadiéndolos en una lista de objetos. Por ejemplo, se puede crear el objeto Telefono compuesto por fijo:int y movil:int y anidarlo en el objeto Agenda. Incluso podemos incluir listas dentro de esos objetos (por ejemplo, en Agenda podemos crear Grupo:new list of string que contenga “amigos, familia, trabajo”. Las posibilidades son muchas.
Diccionarios
Antes de usar los diccionarios recuerda lo que se comentó para las listas en cuanto a dependencias y compilación.
Los diccionarios (dict) son una colección desordenada de elementos accesibles por índices de tipo arbitrario. Pueden utilizarse como tablas de consulta y para asignar rápidamente valores.
Formalmente consisten en pares de una clave (key) con un valor. Los podemos imaginar como una tabla de dos columnas, siendo la primera columna las claves y la segunda los valores. Se accede a sus valores a través de sus claves
Al crear uno nuevo es necesario especificar los tipos de clave y valor:
var contacto = new dict of string,string var agenda = new dict of string,int
Como en las listas, sus claves y valores también pueden iterarse con la instrucción for..in.
Se pueden añadir elementos usando el método add y también con agenda[clave]=valor.
// compilar con valac --pkg gee-0.8 nombre_archivo.gs init // creamos el diccionario var capitales = new dict of string,string // incorporamos elementos capitales["Italia"] = "Roma" capitales["Rusia"] = "Moscu" capitales["Argentina"] = "Buenos Aires" capitales["Francia"] = "Tokio" // Rescatamos un valor por su clave print "La capital de Rusia es %s",capitales["Rusia"] // otra forma de añadir elementos capitales.set("Japon","Tokio") // cambiamos el valor de una clave capitales.set("Francia","Paris") print "La capital de Francia es %s", capitales.get("Francia") // comprobamos que existe una clave *** OBSOLETO *** if capitales.contains("Argentina") == true print "Argentina esta en el diccionario." // comprobar que existe una clave if capitales.has_key("Argentina") == true print "Argentina esta en el diccionario." // recorremos las claves for pais in capitales.keys print pais // recorremos los valores for ciudad in capitales.values print ciudad // recorremos las claves y extraemos ambos for capi in capitales.keys print("Pais: %s -- Capital: %s", capi, capitales[capi]) // eliminamos elemento capitales.remove("Rusia") // la clave puede ser una variable var k = "Italia" print "%s", capitales[k]