4.4. Cadenas de caracteres
4.4.1. Definición. Lectura desde teclado
Hemos visto cómo leer cadenas de caracteres (Console.ReadLine) y cómo mostrarlas en pantalla (Console.Write), así como la forma de darles un valor(=). También podemos comparar cual es su valor, usando ==, o formar una cadena a partir de otras si las unimos con el símbolo de la suma (+):
Así, un ejemplo que nos pidiese nuestro nombre y nos saludase usando todas estas posibilidades podría ser:
/*---------------------------*/ /* Ejemplo en C# nº 42: */ /* ejemplo42.cs */ /* */ /* Cadenas de texto (1) */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; public class Ejemplo42 { public static void Main() { string saludo = "Hola"; string segundoSaludo; string nombre, despedida; segundoSaludo = "Que tal?"; Console.WriteLine("Dime tu nombre... "); nombre = Console.ReadLine(); Console.WriteLine("{0} {1}", saludo, nombre); Console.WriteLine(segundoSaludo); if (nombre == "Alberto") Console.WriteLine("Dices que eres Alberto?"); else Console.WriteLine("Así que no eres Alberto?"); despedida = "Adios " + nombre + "!"; Console.WriteLine(despedida); } }
4.4.2. Cómo acceder a las letras que forman una cadena
Podemos leer (o modificar) una de las letras de una cadena de igual forma que leemos los elementos de cualquier array: si la cadena se llama "texto", el primer elemento será texto[0], el segundo será texto[1] y así sucesivamente.
Eso sí, las cadenas en C# no se pueden modificar letra a letra: no podemos hacer texto[0]=’a’. Para eso habrá que usar una construcción auxiliar, que veremos más adelante.
4.4.3. Longitud de la cadena.
Podemos saber cuantas letras forman una cadena con "cadena.Length". Esto permite que podamos recorrer la cadena letra por letra, usando construcciones como "for".
Ejercicio propuesto: Un programa te pida tu nombre y lo muestre en pantalla separando cada letra de la siguiente con un espacio. Por ejemplo, si tu nombre es "Juan", debería aparecer en pantalla "J u a n".
4.4.4. Extraer una subcadena
Podemos extraer parte del contenido de una cadena con "Substring", que recibe dos parámetros: la posición a partir de la que queremos empezar y la cantidad de caracteres que queremos obtener. El resultado será otra cadena:
saludo = frase.Substring(0,4);
Podemos omitir el segundo número, y entonces se extraerá desde la posición indicada hasta el final de la cadena.
4.4.5. Buscar en una cadena
Para ver si una cadena contiene un cierto texto, podemos usar IndexOf ("posición de"), que nos dice en qué posición se encuentra (o devuelve el valor -1 si no aparece):
if (nombre.IndexOf("Juan") >= 0) Console.Write("Bienvenido, Juan");
Podemos añadir un segundo parámetro opcional, que es la posición a partir de la que queremos buscar:
if (nombre.IndexOf("Juan", 5) >= 0) ...
La búsqueda termina al final de la cadena, salvo que indiquemos que termine antes con un tercer parámetro opcional:
if (nombre.IndexOf("Juan", 5, 15) >= 0) ...
De forma similar, LastIndexOf ("última posición de") indica la última aparición (es decir, busca de derecha a izquierda).
4.4.6. Otras manipulaciones de cadenas
Ya hemos comentado que las cadenas en C# son inmutables, no se pueden modificar. Pero sí podemos realizar ciertas operaciones sobre ellas para obtener una nueva cadena. Por ejemplo:
- ToUpper() convierte a mayúsculas: nombreCorrecto = nombre.ToUpper();
- ToLower() convierte a minúsculas: password2 = password.ToLower();
- Insert(int posición, string subcadena): Insertar una subcadena en una cierta posición de la cadena inicial: nombreFormal = nombre.Insert(0,"Don");
- Remove(int posición, int cantidad): Elimina una cantidad de caracteres en cierta posición: apellidos = nombreCompleto.Remove(0,6);
- Replace(string textoASustituir, string cadenaSustituta): Sustituye una cadena (todas las veces que aparezca) por otra: nombreCorregido = nombre.Replace("Pepe", "Jose");
Un programa que probara todas estas posibilidades podría ser así:
/*---------------------------*/ /* Ejemplo en C# nº 43: */ /* ejemplo43.cs */ /* */ /* Cadenas de texto (2) */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; public class Ejemplo43 { public static void Main() { string ejemplo = "Hola, que tal estas"; Console.WriteLine("El texto es: {0}", ejemplo); Console.WriteLine("La primera letra es: {0}", ejemplo[0]); Console.WriteLine("Las tres primeras letras son: {0}", ejemplo.Substring(0,3)); Console.WriteLine("La longitud del texto es: {0}", ejemplo.Length); Console.WriteLine("La posicion de \"que\" es: {0}", ejemplo.IndexOf("que")); Console.WriteLine("La ultima A esta en la posicion: {0}", ejemplo.LastIndexOf("a")); Console.WriteLine("En mayúsculas: {0}", ejemplo.ToUpper()); Console.WriteLine("En minúsculas: {0}", ejemplo.ToLower()); Console.WriteLine("Si insertamos \", tio\": {0}", ejemplo.Insert(4,", tio")); Console.WriteLine("Si borramos las 6 primeras letras: {0}", ejemplo.Remove(0, 6)); Console.WriteLine("Si cambiamos ESTAS por ESTAMOS: {0}", ejemplo.Replace("estas", "estamos")); } }
Y su resultado sería
El texto es: Hola, que tal estas
La primera letra es: H
Las tres primeras letras son: Hol
La longitud del texto es: 19
La posicion de "que" es: 6
La ultima A esta en la posicion: 17
En mayúsculas: HOLA, QUE TAL ESTAS
En minúsculas: hola, que tal estas
Si insertamos ", tio": Hola, tio, que tal estas
Si borramos las 6 primeras letras: que tal estas
Si cambiamos ESTAS por ESTAMOS: Hola, que tal estamos
Otra posibilidad interesante, aunque un poco más avanzada, es la de descomponer una cadena en trozos, que estén separados por una serie de delimitadores (por ejemplo, espacios o comas). Para ello se puede usar Split, que crea un array a partir de los fragmentos de la cadena, así:
/*---------------------------*/ /* Ejemplo en C# nº 43b: */ /* ejemplo43b.cs */ /* */ /* Cadenas de texto (2b) */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; public class Ejemplo43b { public static void Main() { string ejemplo = "uno,dos.tres,cuatro"; char [] delimitadores = {',', '.'}; int i; string [] ejemploPartido = ejemplo.Split(delimitadores); for (i=0; i<ejemploPartido.Length; i++) Console.WriteLine("Fragmento {0}= {1}", i, ejemploPartido[i]); } }
Que mostraría en pantalla lo siguiente:
Fragmento 0= uno
Fragmento 1= dos
Fragmento 2= tres
Fragmento 3= cuatro
4.4.7. Comparación de cadenas
Sabemos comprobar si una cadena tiene exactamente un cierto valor, con el operador de igualdad (==), pero no sabemos comparar qué cadena es "mayor" que otra, algo que es necesario si queremos ordenar textos. El operador "mayor que" (>) que usamos con los números no se puede aplicar directamente a las cadenas. En su lugar, debemos usar "CompareTo", que devolverá un número mayor que 0 si la nuestra cadena es mayor que la que indicamos como parámetro (o un número negativo si nuestra cadena es menor, o 0 si son iguales):
if (frase.CompareTo("hola") > 0) Console.WriteLine("Es mayor que hola");
También podemos comparar sin distinguir entre mayúsculas y minúsculas, usando String.Compare, al que indicamos las dos cadenas y un tercer dato "true" cuando queramos ignorar esa distinción:
if (String.Compare(frase, "hola", true) > 0) Console.WriteLine("Es mayor que hola (mays o mins)");
Un programa completo de prueba podría ser así:
/*---------------------------*/ /* Ejemplo en C# nº 43c: */ /* ejemplo43c.cs */ /* */ /* Cadenas de texto (2c) */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; public class Ejemplo43c { public static void Main() { string frase; Console.WriteLine("Escriba una palabra"); frase = Console.ReadLine(); // Compruebo si es exactamente hola if (frase == "hola") Console.WriteLine("Ha escrito hola"); // Compruebo si es mayor o menor if (frase.CompareTo("hola") > 0) Console.WriteLine("Es mayor que hola"); else if (frase.CompareTo("hola") < 0) Console.WriteLine("Es menor que hola"); // Comparo sin distinguir mayúsculas ni minúsculas bool ignorarMays = true; if (String.Compare(frase, "hola", ignorarMays) > 0) Console.WriteLine("Es mayor que hola (mays o mins)"); else if (String.Compare(frase, "hola", ignorarMays) < 0) Console.WriteLine("Es menor que hola (mays o mins)"); else Console.WriteLine("Es hola (mays o mins)"); } }
Si tecleamos una palabra como "gol", que comienza por G, que alfabéticamente está antes de la H de "hola", se nos dirá que esa palabra es menor:
Escriba una palabra
gol
Es menor que hola
Es menor que hola (mays o mins)
Si escribimos "hOLa", que coindice con "hola" salvo por las mayúsculas, una comparación normal nos dirá que es mayor (las mayúsculas se consideran "mayores" que las minúsculas), y una comparación sin considerar mayúsculas o minúsculas nos dirá que coinciden:
Escriba una palabra
hOLa
Es mayor que hola
Es hola (mays o mins)
4.4.8. Una cadena modificable: StringBuilder
Si tenemos la necesidad de poder modificar una cadena letra a letra, no podemos usar un "string" convencional, deberemos recurrir a un "StringBuilder", que sí lo permiten pero son algo más complejos de manejar: hay de reservarles espacio con "new" (igual que hacíamos en ciertas ocasiones con los Arrays), y se pueden convertir a una cadena "convencional" usando "ToString":
/*---------------------------*/ /* Ejemplo en C# nº 44: */ /* ejemplo44.cs */ /* */ /* Cadenas modificables */ /* con "StringBuilder" */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; using System.Text; // Usaremos un System.Text.StringBuilder public class Ejemplo44 { public static void Main() { StringBuilder cadenaModificable = new StringBuilder("Hola"); cadenaModificable[0] = 'M'; Console.WriteLine("Cadena modificada: {0}", cadenaModificable); string cadenaNormal; cadenaNormal = cadenaModificable.ToString(); Console.WriteLine("Cadena normal a partir de ella: {0}", cadenaNormal); } }
Ejercicio propuesto:
- Un programa que pida tu nombre, tu día de nacimiento y tu mes de nacimiento y lo junte todo en una cadena, separando el nombre de la fecha por una coma y el día del mes por una barra inclinada, así: "Juan, nacido el 31/12".
- Crear un juego del ahorcado, en el que un primer usuario introduzca la palabra a adivinar, se muestre esta programa oculta con guiones (-----) y el programa acepte las letras que introduzca el segundo usuario, cambiando los guiones por letras correctas cada vez que acierte (por ejemplo, a---a-t-). La partida terminará cuando se acierte la palabra por completo o el usuario agote sus 8 intentos.
4.4.9. Recorriendo con "foreach"
Existe una construcción parecida a "for", pensada para recorrer ciertas estructuras de datos, como los arrays (y otras que veremos más adelante).
Se usa con el formato "foreach (variable in ConjuntoDeValores)":
/*---------------------------*/ /* Ejemplo en C# nº 45: */ /* ejemplo45.cs */ /* */ /* Ejemplo de "foreach" */ /* */ /* Introduccion a C#, */ /* Nacho Cabanes */ /*---------------------------*/ using System; public class Ejemplo45 { public static void Main() { int[] diasMes = {31, 28, 21}; foreach(int dias in diasMes) { Console.WriteLine("Dias del mes: {0}", dias); } string[] nombres = {"Alberto", "Andrés", "Antonio"}; foreach(string nombre in nombres) { Console.Write(" {0}", nombre); } Console.WriteLine(); string saludo = "Hola"; foreach(char letra in saludo) { Console.Write("{0}-", letra); } Console.WriteLine(); } }