Módulo 06: Cadenas de texto
Objetivos del módulo
- Dominar el tipo
stringy sus métodos más útiles - Entender la inmutabilidad de los strings
- Usar interpolación y formateo de cadenas
- Trabajar con
StringBuilderpara rendimiento - Conocer expresiones regulares básicas
1. El tipo string en profundidad
Ya conocemos string del módulo de tipos de datos. Ahora vamos a profundizar en todo lo que puedes hacer con él.
📘 Concepto: Un
stringen C# es inmutable: una vez creado, no se puede modificar. Cada vez que “modificas” un string, en realidad se crea uno nuevo en memoria. El original queda intacto.
string nombre = "Ana";
string nombreMayus = nombre.ToUpper(); // Se crea un NUEVO string
Console.WriteLine(nombre); // "Ana" (el original no cambia)
Console.WriteLine(nombreMayus); // "ANA" (es una copia nueva)
2. Métodos de string más utilizados
Búsqueda y comprobación
string texto = "Hola, bienvenido al curso de C#";
// Longitud
Console.WriteLine($"Longitud: {texto.Length}"); // 31
// Contiene
Console.WriteLine(texto.Contains("curso")); // True
Console.WriteLine(texto.Contains("Python")); // False
// Empieza con / Termina con
Console.WriteLine(texto.StartsWith("Hola")); // True
Console.WriteLine(texto.EndsWith("C#")); // True
// Posición de un substring
int pos = texto.IndexOf("curso");
Console.WriteLine($"'curso' está en posición {pos}"); // 22
int noExiste = texto.IndexOf("Java");
Console.WriteLine($"'Java' está en posición {noExiste}"); // -1 (no encontrado)
// Está vacío o nulo
string vacio = "";
string? nulo = null;
Console.WriteLine(string.IsNullOrEmpty(vacio)); // True
Console.WriteLine(string.IsNullOrEmpty(nulo)); // True
Console.WriteLine(string.IsNullOrWhiteSpace(" ")); // True (solo espacios)
Transformación
string texto = " Hola, Mundo ";
// Mayúsculas y minúsculas
Console.WriteLine(texto.ToUpper()); // " HOLA, MUNDO "
Console.WriteLine(texto.ToLower()); // " hola, mundo "
// Eliminar espacios
Console.WriteLine($"[{texto.Trim()}]"); // "[Hola, Mundo]"
Console.WriteLine($"[{texto.TrimStart()}]"); // "[Hola, Mundo ]"
Console.WriteLine($"[{texto.TrimEnd()}]"); // "[ Hola, Mundo]"
// Reemplazar
string nuevo = texto.Trim().Replace("Mundo", "C#");
Console.WriteLine(nuevo); // "Hola, C#"
// Insertar y eliminar
string base1 = "Hola Mundo";
Console.WriteLine(base1.Insert(5, "Buen ")); // "Hola Buen Mundo"
Console.WriteLine(base1.Remove(5)); // "Hola " (elimina desde índice 5)
Console.WriteLine(base1.Remove(5, 3)); // "Hola do" (elimina 3 chars desde índice 5)
Extraer partes (Substring)
string email = "usuario@correo.com";
// Substring(inicio): desde la posición hasta el final
string dominio = email.Substring(email.IndexOf('@') + 1);
Console.WriteLine(dominio); // "correo.com"
// Substring(inicio, longitud)
string usuario = email.Substring(0, email.IndexOf('@'));
Console.WriteLine(usuario); // "usuario"
// Forma moderna con rangos
string dominio2 = email[(email.IndexOf('@') + 1)..];
string usuario2 = email[..email.IndexOf('@')];
Dividir y unir (Split/Join)
// Split: dividir un string en un array
string csv = "Ana,Luis,María,Pedro,Carmen";
string[] nombres = csv.Split(',');
foreach (string nombre in nombres)
{
Console.WriteLine(nombre);
}
// Ana
// Luis
// María
// Pedro
// Carmen
// Join: unir un array en un string
string unido = string.Join(" - ", nombres);
Console.WriteLine(unido); // "Ana - Luis - María - Pedro - Carmen"
// Split con múltiples separadores
string datos = "nombre=Ana; edad=25; ciudad=Madrid";
string[] pares = datos.Split(new[] { ';', '=' }, StringSplitOptions.TrimEntries);
// { "nombre", "Ana", "edad", "25", "ciudad", "Madrid" }
// Split por líneas
string multilinea = "línea 1\nlínea 2\nlínea 3";
string[] lineas = multilinea.Split('\n');
Rellenar y alinear (PadLeft/PadRight)
// PadLeft: rellenar por la izquierda
string numero = "42";
Console.WriteLine(numero.PadLeft(5, '0')); // "00042"
Console.WriteLine(numero.PadLeft(8)); // " 42" (rellena con espacios)
// PadRight: rellenar por la derecha
string nombre = "Ana";
Console.WriteLine($"|{nombre.PadRight(10)}|"); // "|Ana |"
// Útil para tablas alineadas
string[] items = { "Manzana", "Pan", "Leche" };
double[] precios = { 1.50, 0.80, 1.20 };
for (int i = 0; i < items.Length; i++)
{
Console.WriteLine($"{items[i].PadRight(12)} {precios[i],6:C2}");
}
// Manzana 1,50 €
// Pan 0,80 €
// Leche 1,20 €
3. Interpolación de cadenas
La interpolación es la forma moderna y recomendada de construir strings con variables:
string nombre = "Ana";
int edad = 25;
// Concatenación clásica (NO recomendada)
string msg1 = "Hola, " + nombre + ". Tienes " + edad + " años.";
// Interpolación (RECOMENDADA)
string msg2 = $"Hola, {nombre}. Tienes {edad} años.";
// Puedes poner expresiones dentro de { }
string msg3 = $"El doble de tu edad es {edad * 2}";
string msg4 = $"En mayúsculas: {nombre.ToUpper()}";
// Formato numérico dentro de interpolación
double precio = 1234.5;
Console.WriteLine($"Precio: {precio:C2}"); // Moneda: 1.234,50 €
Console.WriteLine($"Precio: {precio:N2}"); // Número: 1.234,50
Console.WriteLine($"Precio: {precio:F2}"); // Fixed: 1234,50
Console.WriteLine($"Porcentaje: {0.256:P1}"); // 25,6 %
// Alineación
Console.WriteLine($"|{"Izquierda",-15}|{"Derecha",15}|");
// |Izquierda | Derecha|
Formatos numéricos
| Formato | Descripción | Ejemplo (1234.5) |
|---|---|---|
C / C2 | Moneda | 1.234,50 € |
N / N2 | Número con separadores | 1.234,50 |
F / F2 | Decimal fijo | 1234,50 |
P / P1 | Porcentaje | 123.450,0 % |
E | Notación científica | 1,234500E+003 |
D5 | Entero con ceros a la izquierda | 01234 |
X | Hexadecimal | 4D2 |
Formatos de fecha
DateTime ahora = DateTime.Now;
Console.WriteLine($"Completa: {ahora}");
Console.WriteLine($"Solo fecha: {ahora:d}"); // 30/03/2026
Console.WriteLine($"Fecha larga: {ahora:D}"); // lunes, 30 de marzo de 2026
Console.WriteLine($"Solo hora: {ahora:t}"); // 14:30
Console.WriteLine($"Personalizado: {ahora:dd/MM/yyyy HH:mm}"); // 30/03/2026 14:30
4. Cadenas verbatim y raw strings
Cadenas verbatim (@)
El prefijo @ permite escribir strings sin que las barras invertidas se interpreten como secuencias de escape:
// Sin @: necesitas escapar las barras
string ruta1 = "C:\\Users\\Ana\\Documentos\\archivo.txt";
// Con @: las barras se escriben directamente
string ruta2 = @"C:\Users\Ana\Documentos\archivo.txt";
// También permite multilínea
string multilinea = @"Esta es la primera línea.
Esta es la segunda línea.
Esta es la tercera línea.";
Raw string literals (C# 11+)
Las raw strings usan triple comilla """ y son la forma más limpia de escribir texto complejo:
// Raw string literal
string json = """
{
"nombre": "Ana",
"edad": 25,
"ciudad": "Madrid"
}
""";
Console.WriteLine(json);
// Raw string con interpolación
string nombre = "Ana";
int edad = 25;
string jsonDinamico = $"""
{{
"name": "{nombre}",
"age": {edad}
}}
""";
💡 Consejo: Usa raw strings (
""") cuando necesites escribir JSON, XML, HTML, SQL u otro texto con muchos caracteres especiales. Son mucho más legibles que escapar cada carácter.
5. Comparación de strings
string a = "hola";
string b = "Hola";
// Comparación sensible a mayúsculas (por defecto)
Console.WriteLine(a == b); // False
// Comparación ignorando mayúsculas
Console.WriteLine(a.Equals(b, StringComparison.OrdinalIgnoreCase)); // True
Console.WriteLine(string.Equals(a, b, StringComparison.OrdinalIgnoreCase)); // True
// Comparar para ordenar
int resultado = string.Compare(a, b, StringComparison.OrdinalIgnoreCase);
// 0 = iguales, < 0 = a va antes, > 0 = a va después
6. StringBuilder: rendimiento con muchas concatenaciones
📘 Concepto: Como los strings son inmutables, cada concatenación crea un nuevo string en memoria. Si haces muchas concatenaciones (por ejemplo, en un bucle), esto es muy ineficiente.
StringBuilderresuelve esto al modificar el texto en el mismo lugar en memoria.
using System.Text; // Necesario para StringBuilder
// MAL: concatenación en bucle (crea 1000 strings intermedios)
string resultado = "";
for (int i = 0; i < 1000; i++)
{
resultado += i + ", "; // Cada += crea un nuevo string
}
// BIEN: StringBuilder (modifica el mismo objeto)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append(i);
sb.Append(", ");
}
string resultadoFinal = sb.ToString();
Métodos de StringBuilder
StringBuilder sb = new StringBuilder();
sb.Append("Hola"); // Añadir al final
sb.Append(" mundo");
sb.AppendLine("!"); // Añadir + salto de línea
sb.AppendLine("¿Qué tal?");
sb.Insert(5, ", buen"); // Insertar en posición
sb.Replace("mundo", "mundo maravilloso"); // Reemplazar
Console.WriteLine(sb.ToString());
Console.WriteLine($"Longitud: {sb.Length}");
sb.Clear(); // Vaciar todo
💡 Consejo: Regla general: si concatenas strings menos de 5-10 veces, usa
+o interpolación. Si concatenas en un bucle o más de 10 veces, usaStringBuilder.
7. Expresiones regulares básicas
Las expresiones regulares (regex) permiten buscar patrones complejos en texto:
using System.Text.RegularExpressions;
string texto = "Mi email es ana@correo.com y mi teléfono es 612345678";
// Buscar un patrón de email
bool tieneEmail = Regex.IsMatch(texto, @"[\w.]+@[\w.]+\.\w+");
Console.WriteLine($"¿Tiene email? {tieneEmail}"); // True
// Extraer el email
Match match = Regex.Match(texto, @"[\w.]+@[\w.]+\.\w+");
Console.WriteLine($"Email encontrado: {match.Value}"); // ana@correo.com
// Buscar números de teléfono (9 dígitos)
Match telefono = Regex.Match(texto, @"\d{9}");
Console.WriteLine($"Teléfono: {telefono.Value}"); // 612345678
// Validar formato
string email = "usuario@ejemplo.com";
bool emailValido = Regex.IsMatch(email, @"^[\w.]+@[\w.]+\.\w{2,}$");
Console.WriteLine($"¿Email válido? {emailValido}"); // True
// Reemplazar con regex
string censurado = Regex.Replace(texto, @"\d{9}", "***-***-***");
Console.WriteLine(censurado);
Patrones regex comunes
| Patrón | Significado | Ejemplo |
|---|---|---|
\d | Un dígito (0-9) | \d{3} → tres dígitos |
\w | Letra, dígito o _ | \w+ → una o más letras |
\s | Espacio en blanco | \s+ → uno o más espacios |
. | Cualquier carácter | a.c → “abc”, “a1c”, etc. |
+ | Uno o más | \d+ → uno o más dígitos |
* | Cero o más | \d* → cero o más dígitos |
? | Cero o uno | colou?r → “color” o “colour” |
^ | Inicio de cadena | ^Hola → empieza con “Hola” |
$ | Fin de cadena | com$ → termina con “com” |
[abc] | Cualquiera de estos caracteres | [aeiou] → vocal |
{n} | Exactamente n veces | \d{4} → exactamente 4 dígitos |
8. Ejercicios
Ejercicio 1: Contador de vocales
Pide una frase al usuario y cuenta cuántas vocales tiene (sin distinguir mayúsculas/minúsculas).
Ejercicio 2: Palíndromo
Comprueba si una palabra es un palíndromo (se lee igual al derecho y al revés): “ana”, “radar”, “reconocer”.
Pista:
string invertida = new string(palabra.Reverse().ToArray());
Ejercicio 3: Cifrado César
Implementa un cifrado César simple: desplaza cada letra 3 posiciones en el alfabeto.
- “abc” → “def”
- “xyz” → “abc” (vuelve al inicio)
Ejercicio 4: Validador de contraseñas
Crea un programa que valide si una contraseña cumple:
- Al menos 8 caracteres
- Al menos una mayúscula
- Al menos una minúscula
- Al menos un número
- Al menos un carácter especial (!@#$%^&*)
Ejercicio 5: Analizador de texto
Pide un texto al usuario y muestra:
- Número de caracteres
- Número de palabras
- Número de frases (terminan en
.,!o?) - Palabra más larga
- Palabra más frecuente
Resumen
| Método/Concepto | Descripción |
|---|---|
str.Length | Longitud del string |
str.ToUpper() / ToLower() | Cambiar mayúsculas/minúsculas |
str.Trim() | Eliminar espacios al inicio y final |
str.Contains("x") | ¿Contiene este texto? |
str.StartsWith("x") | ¿Empieza con…? |
str.IndexOf("x") | Posición de la primera ocurrencia (-1 si no existe) |
str.Replace("a", "b") | Reemplazar texto |
str.Split(',') | Dividir en array |
string.Join("-", array) | Unir array en string |
str.Substring(i, n) | Extraer parte del string |
$"Hola {var}" | Interpolación |
@"C:\ruta" | Cadena verbatim |
"""texto""" | Raw string literal |
StringBuilder | Concatenación eficiente en bucles |
Regex | Búsqueda y validación con patrones |