Conversión de tipos y operaciones con cadenas
Introducción
En la programación, es habitual necesitar convertir datos de un tipo a otro para adaptarlos a diferentes necesidades. Por ejemplo, podríamos necesitar convertir un número entero a decimal para realizar cálculos más precisos, o transformar un número en una cadena de texto para mostrarlo en pantalla. En C#, estas conversiones de tipos son operaciones fundamentales que todo programador debe dominar.
Por otro lado, las cadenas de texto (strings) son uno de los tipos de datos más utilizados en cualquier aplicación. Desde la interfaz de usuario hasta el procesamiento de información, las operaciones con cadenas son esenciales en el desarrollo de software. C# ofrece un amplio conjunto de herramientas para manipular texto de forma eficiente y flexible.
En este artículo, exploraremos tanto las técnicas de conversión entre diferentes tipos de datos como las operaciones más comunes con cadenas de texto en C#. Estos conocimientos nos permitirán manejar datos de forma más versátil en nuestras aplicaciones.
Conversión de tipos en C#
La conversión de tipos, también conocida como "casting" o "type casting", es el proceso de transformar un valor de un tipo de datos a otro. En C#, existen diferentes mecanismos para realizar estas conversiones, cada uno con sus propias características y casos de uso.
Tipos de conversiones
En C#, las conversiones se clasifican principalmente en dos categorías:
Tipo de conversión | Descripción | Características |
---|---|---|
Implícita | Conversiones automáticas que C# realiza sin intervención del programador | No hay pérdida de datos. El tipo de destino puede almacenar cualquier valor del tipo de origen |
Explícita | Conversiones que requieren una sintaxis específica por parte del programador | Puede haber pérdida de datos. El programador acepta conscientemente este riesgo |
Conversiones implícitas
Las conversiones implícitas son aquellas que C# realiza automáticamente cuando no existe riesgo de pérdida de datos. Estas conversiones siguen una jerarquía natural de tipos, donde los tipos "menores" pueden convertirse a tipos "mayores" sin perder información.
Algunos ejemplos de conversiones implícitas comunes incluyen:
Conversión | Ejemplo |
---|---|
int a long | Un entero de 32 bits cabe perfectamente en un entero de 64 bits |
int a double | Un entero se puede representar exactamente como un número de punto flotante |
char a int | El valor Unicode del carácter se convierte a su representación numérica |
Tipos derivados a tipos base | Una clase derivada siempre puede tratarse como su clase base |
// Conversión implícita de int a long
int entero = 123;
long numeroLargo = entero; // Conversión automática, no hay pérdida de datos
Console.WriteLine($"Entero: {entero}, Long: {numeroLargo}");
// Conversión implícita de int a double
double decimal1 = entero; // 123 se convierte automáticamente a 123.0
Console.WriteLine($"Entero: {entero}, Double: {decimal1}");
// Conversión implícita de char a int (se obtiene el valor Unicode)
char caracter = 'A';
int valorUnicode = caracter; // 'A' se convierte al valor 65
Console.WriteLine($"Caracter: {caracter}, Valor Unicode: {valorUnicode}");
// Conversión implícita en expresiones mixtas
int x = 5;
double y = 2.5;
double resultado = x + y; // x se convierte implícitamente a double antes de la suma
Console.WriteLine($"{x} + {y} = {resultado}"); // 5 + 2.5 = 7.5
Conversiones explícitas
Las conversiones explícitas son necesarias cuando existe riesgo de pérdida de datos o cuando C# no puede garantizar que la conversión sea segura. En estos casos, el programador debe indicar explícitamente su intención de realizar la conversión, aceptando el riesgo potencial.
Sintaxis básica para conversiones explícitas:
(TipoDestino)expresión
Situaciones que requieren conversiones explícitas:
Situación | Descripción | Riesgo potencial |
---|---|---|
Conversión de punto flotante a entero | Pasar de double/float a int/long | Pérdida de la parte decimal |
Entero mayor a entero menor | Pasar de long a int, o de int a short | Desbordamiento si el valor excede el rango del tipo destino |
Clase base a clase derivada | Tratar un objeto de clase base como clase derivada | Excepción en tiempo de ejecución si el objeto no es realmente del tipo derivado |
// Conversión explícita de double a int (se pierde la parte decimal)
double numeroDecimal = 123.75;
int enteroConvertido = (int)numeroDecimal; // Casting explícito
Console.WriteLine($"Double: {numeroDecimal}, Int convertido: {enteroConvertido}"); // 123.75 -> 123
// Conversión explícita de long a int (podría causar desbordamiento)
long numeroGrande = 2147483647; // Valor máximo de int
int enteroResultante = (int)numeroGrande;
Console.WriteLine($"Long: {numeroGrande}, Int convertido: {enteroResultante}");
// Cuidado con los desbordamientos
long demasiadoGrande = 9223372036854775807; // Un número que excede el rango de int
int intentoConversion = (int)demasiadoGrande; // Causa pérdida de datos
Console.WriteLine($"Valor original: {demasiadoGrande}, Valor convertido: {intentoConversion}");
Métodos de conversión en C#
Además de las conversiones implícitas y explícitas básicas, C# proporciona varios métodos y clases para realizar conversiones de manera más controlada y segura.
La clase Convert
La clase Convert
proporciona métodos para convertir entre tipos de datos comunes. Esta clase maneja valores nulos de manera apropiada y ofrece conversiones más seguras entre tipos incompatibles.
Métodos principales de la clase Convert:
Método | Descripción |
---|---|
ToBoolean() |
Convierte un valor a un booleano |
ToInt32() |
Convierte un valor a un entero de 32 bits |
ToDouble() |
Convierte un valor a un número de punto flotante double |
ToString() |
Convierte un valor a una cadena de texto |
ToDateTime() |
Convierte un valor a un objeto DateTime |
Comportamiento con valores nulos:
- Los métodos de la clase
Convert
conviertennull
a valores predeterminados para el tipo de destino (0 para tipos numéricos, falso para booleanos, etc.)
// Convertir string a tipos numéricos
string numeroTexto = "123";
int numeroEntero = Convert.ToInt32(numeroTexto);
double numeroDouble = Convert.ToDouble(numeroTexto);
Console.WriteLine($"String: {numeroTexto}, Int: {numeroEntero}, Double: {numeroDouble}");
// Convertir booleano a otros tipos
bool verdadero = true;
int boolComoInt = Convert.ToInt32(verdadero); // true -> 1
string boolComoString = Convert.ToString(verdadero); // true -> "True"
Console.WriteLine($"Bool: {verdadero}, Int: {boolComoInt}, String: {boolComoString}");
// Gestión de valores nulos
string valorNulo = null;
int resultadoNulo = Convert.ToInt32(valorNulo); // null -> 0
Console.WriteLine($"String nulo convertido a int: {resultadoNulo}");
Métodos Parse y TryParse
Los tipos numéricos y de fecha en C# proporcionan métodos Parse
y TryParse
para convertir cadenas a esos tipos específicos.
Comparación entre Parse y TryParse:
Característica | Parse | TryParse |
---|---|---|
Comportamiento con formatos inválidos | Lanza una excepción | Devuelve false y un valor predeterminado |
Valor de retorno | El valor convertido | Booleano (éxito/fallo) y el valor convertido como parámetro de salida |
Uso recomendado | Cuando estamos seguros del formato | En aplicaciones reales donde el formato puede variar |
Opciones de formato:
- Los métodos
Parse
yTryParse
pueden aceptar información de cultura para interpretar correctamente números con diferentes formatos regionales (punto o coma como separador decimal, por ejemplo).
// Método Parse - Lanza excepción si la conversión falla
string numeroValido = "42";
int numero = int.Parse(numeroValido);
Console.WriteLine($"String parseado: {numeroValido} -> {numero}");
// Método TryParse - No lanza excepción si falla, devuelve un booleano indicando éxito
string posibleNumero = "123.45";
if (int.TryParse(posibleNumero, out int resultado))
{
Console.WriteLine($"Conversión exitosa: {posibleNumero} -> {resultado}");
}
else
{
Console.WriteLine($"No se pudo convertir '{posibleNumero}' a int");
}
// TryParse con float - Más adecuado para este caso
if (float.TryParse(posibleNumero, out float resultadoFloat))
{
Console.WriteLine($"Conversión a float exitosa: {posibleNumero} -> {resultadoFloat}");
}
// Parseo con formato específico de cultura
string numeroConComa = "1.234,56"; // Formato español con punto como separador de miles
double resultadoCultura = double.Parse(
numeroConComa,
System.Globalization.NumberStyles.Number,
System.Globalization.CultureInfo.GetCultureInfo("es-ES")
);
Console.WriteLine($"Número con formato español: {numeroConComa} -> {resultadoCultura}");
Operadores as e is
Para tipos de referencia y tipos anulables, C# proporciona los operadores as
e is
que permiten realizar comprobaciones de tipo y conversiones de manera segura.
Operador is:
- Comprueba si un objeto es compatible con un tipo específico
- Devuelve un valor booleano (true/false)
- En C# moderno, puede combinarse con pattern matching para declarar variables
Operador as:
- Intenta convertir un objeto a un tipo específico
- Devuelve null si la conversión no es posible
- Solo funciona con tipos de referencia y tipos anulables
- No lanza excepciones
object objetoString = "Esto es una cadena";
// Operador is - Comprueba si el objeto es de un tipo específico
if (objetoString is string)
{
Console.WriteLine("El objeto es una cadena");
}
// Operador as - Intenta convertir y devuelve null si no es posible
string cadenaSacada = objetoString as string;
if (cadenaSacada != null)
{
Console.WriteLine($"Cadena extraída: {cadenaSacada}");
}
// Pattern matching en C# moderno (C# 7.0+)
if (objetoString is string texto)
{
// La variable 'texto' está disponible y ya es de tipo string
Console.WriteLine($"Usando pattern matching: {texto}");
}
Operaciones con cadenas
Las cadenas de texto (tipo string
) son uno de los tipos de datos más utilizados en programación. En C#, las cadenas son objetos inmutables, lo que significa que una vez creadas, su contenido no puede ser modificado. Cualquier operación que parezca modificar una cadena en realidad está creando una nueva cadena.
Creación y asignación de cadenas
Existen varias formas de crear y asignar cadenas en C#:
Método | Sintaxis | Descripción |
---|---|---|
Asignación directa | string cadena = "texto"; |
Forma básica y más común |
Constructor | string cadena = new string(caracteres); |
Crea una cadena a partir de un array de caracteres |
Cadena vacía | string cadena = string.Empty; |
Crear una cadena vacía (preferible a "" ) |
Cadena literal verbatim | string ruta = @"C:\Archivos\texto.txt"; |
Usando @ para ignorar caracteres de escape |
Interpolación | string mensaje = $"Hola, {nombre}"; |
Usando $ para incluir variables en cadenas |
// Asignación directa
string saludo = "Hola mundo";
// Usando constructor de string (menos común)
char[] letras = { 'H', 'o', 'l', 'a' };
string palabra = new string(letras);
// Cadena vacía
string vacia = string.Empty; // Preferible a string vacia = "";
// Cadena literal verbatim (con @)
string ruta = @"C:\Usuarios\Documentos\archivo.txt"; // No es necesario escapar las barras invertidas
// Interpolación de cadenas (con $)
string nombre = "Ana";
int edad = 30;
string mensaje = $"{nombre} tiene {edad} años";
Console.WriteLine(saludo);
Console.WriteLine(palabra);
Console.WriteLine(mensaje);
Operaciones básicas con cadenas
Concatenación de cadenas
La concatenación es la operación de unir dos o más cadenas para formar una nueva cadena. En C#, existen varias formas de realizar esta operación:
Método | Descripción | Uso recomendado |
---|---|---|
Operador + |
Une dos cadenas | Para concatenaciones simples o pocas operaciones |
Método String.Concat() |
Une múltiples cadenas | Para concatenar múltiples cadenas en una sola operación |
Clase StringBuilder |
Permite construir cadenas de forma incremental | Para muchas concatenaciones o en bucles |
Consideraciones de rendimiento:
- Usar el operador
+
oString.Concat()
para pocas operaciones es eficiente - Para muchas concatenaciones (especialmente en bucles),
StringBuilder
es significativamente más eficiente porque evita crear objetos de cadena intermedios
// Usando el operador +
string primerNombre = "Juan";
string apellido = "García";
string nombreCompleto = primerNombre + " " + apellido;
Console.WriteLine(nombreCompleto); // Juan García
// Usando el método String.Concat
string nombreCompleto2 = string.Concat(primerNombre, " ", apellido);
Console.WriteLine(nombreCompleto2); // Juan García
// Concatenación con StringBuilder (más eficiente para muchas operaciones)
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("Hola ");
sb.Append("a ");
sb.Append("todos");
string resultado = sb.ToString();
Console.WriteLine(resultado); // Hola a todos
Comparación de cadenas
La comparación de cadenas es una operación común que puede realizarse de diversas maneras en C#, cada una con comportamientos específicos:
Método | Sintaxis | Descripción |
---|---|---|
Operador == |
cadena1 == cadena2 |
Compara por igualdad, distingue mayúsculas/minúsculas |
Método Equals() |
cadena1.Equals(cadena2) |
Similar al operador == , pero permite especificar opciones |
Método Compare() |
String.Compare(cadena1, cadena2) |
Compara y devuelve un valor que indica orden relativo |
Método CompareTo() |
cadena1.CompareTo(cadena2) |
Similar a Compare() pero como método de instancia |
Opciones de comparación (StringComparison
):
Opción | Descripción |
---|---|
Ordinal |
Comparación binaria exacta (más rápida) |
OrdinalIgnoreCase |
Comparación binaria sin distinguir mayúsculas/minúsculas |
CurrentCulture |
Respeta reglas de orden alfabético del idioma actual |
InvariantCulture |
Usa reglas de cultura invariante (independiente del idioma local) |
string cadena1 = "hola";
string cadena2 = "HOLA";
string cadena3 = "hola";
// Comparación con igualdad (sensible a mayúsculas/minúsculas)
bool sonIguales = (cadena1 == cadena3);
Console.WriteLine($"¿cadena1 == cadena3? {sonIguales}"); // True
// Comparación con Equals (sensible a mayúsculas/minúsculas)
bool igualdad = cadena1.Equals(cadena2);
Console.WriteLine($"cadena1.Equals(cadena2): {igualdad}"); // False
// Comparación sin distinguir mayúsculas/minúsculas
bool igualdadIgnoreCase = cadena1.Equals(cadena2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"Igualdad ignorando mayúsculas: {igualdadIgnoreCase}"); // True
// Comparación con Compare (devuelve un entero)
int resultadoCompare = string.Compare(cadena1, cadena2, ignoreCase: true);
Console.WriteLine($"Compare ignorando mayúsculas: {resultadoCompare}"); // 0 (son iguales)
// CompareTo (devuelve negativo si la cadena es menor, 0 si son iguales, positivo si es mayor)
int compareTo = cadena1.CompareTo(cadena3);
Console.WriteLine($"cadena1.CompareTo(cadena3): {compareTo}"); // 0 (son iguales)
Búsqueda y manipulación de subcadenas
Propiedades y métodos para examinar cadenas
Propiedad/Método | Descripción |
---|---|
Length |
Devuelve la longitud de la cadena |
IndexOf() |
Busca la primera ocurrencia de un carácter o subcadena |
LastIndexOf() |
Busca la última ocurrencia de un carácter o subcadena |
StartsWith() |
Comprueba si la cadena comienza con un texto específico |
EndsWith() |
Comprueba si la cadena termina con un texto específico |
Contains() |
Comprueba si la cadena contiene un texto específico |
Métodos para modificar cadenas
Recordemos que las cadenas son inmutables en C#, por lo que estos métodos devuelven nuevas cadenas:
Método | Descripción |
---|---|
Substring() |
Extrae una parte de la cadena |
Replace() |
Reemplaza todas las ocurrencias de un texto por otro |
Trim() , TrimStart() , TrimEnd() |
Elimina espacios en blanco al inicio y/o final |
ToUpper() , ToLower() |
Convierte a mayúsculas o minúsculas |
PadLeft() , PadRight() |
Rellena la cadena con caracteres hasta alcanzar una longitud |
string texto = "La programación en C# es divertida y potente";
// Longitud de una cadena
int longitud = texto.Length;
Console.WriteLine($"Longitud: {longitud}");
// Acceso a caracteres individuales
char primerCaracter = texto[0]; // L
char decimoCaracter = texto[9]; // a
Console.WriteLine($"Primer carácter: {primerCaracter}, Décimo carácter: {decimoCaracter}");
// Buscar una subcadena (devuelve el índice o -1 si no la encuentra)
int posicionC = texto.IndexOf("C#");
Console.WriteLine($"Posición de 'C#': {posicionC}"); // 18
// Buscar desde una posición específica
int posicionEs = texto.IndexOf("es", 20);
Console.WriteLine($"Posición de 'es' después del carácter 20: {posicionEs}"); // 21
// Última aparición de un carácter o subcadena
int ultimaA = texto.LastIndexOf("a");
Console.WriteLine($"Última posición de 'a': {ultimaA}"); // 39
// Comprobar si una cadena comienza o termina con una subcadena
bool empiezaConLa = texto.StartsWith("La");
bool terminaConTe = texto.EndsWith("te");
Console.WriteLine($"¿Empieza con 'La'? {empiezaConLa}, ¿Termina con 'te'? {terminaConTe}"); // True, True
// Comprobar si contiene una subcadena
bool contieneProgram = texto.Contains("program");
Console.WriteLine($"¿Contiene 'program'? {contieneProgram}"); // True
string frase = "El aprendizaje de C# requiere práctica constante";
// Extraer una subcadena (desde un índice, con una longitud determinada)
string subcadena1 = frase.Substring(15, 2); // C#
Console.WriteLine($"Subcadena desde posición 15, longitud 2: {subcadena1}");
// Extraer desde un índice hasta el final
string subcadena2 = frase.Substring(15); // C# requiere práctica constante
Console.WriteLine($"Subcadena desde posición 15 hasta el final: {subcadena2}");
// Reemplazar texto
string fraseModificada = frase.Replace("C#", "programación C#");
Console.WriteLine($"Frase con reemplazo: {fraseModificada}");
// Eliminar espacios en blanco al principio y final
string textoConEspacios = " texto con espacios ";
string textoSinEspacios = textoConEspacios.Trim();
Console.WriteLine($"Original: '{textoConEspacios}', Sin espacios: '{textoSinEspacios}'");
// Eliminar solo espacios al principio o al final
string sinInicio = textoConEspacios.TrimStart();
string sinFinal = textoConEspacios.TrimEnd();
Console.WriteLine($"Sin espacios al inicio: '{sinInicio}', Sin espacios al final: '{sinFinal}'");
// Convertir a mayúsculas o minúsculas
string mayusculas = subcadena1.ToUpper();
string minusculas = subcadena1.ToLower();
Console.WriteLine($"Original: {subcadena1}, Mayúsculas: {mayusculas}, Minúsculas: {minusculas}");
División y unión de cadenas
C# proporciona métodos específicos para dividir una cadena en subcadenas y para unir múltiples cadenas:
Método | Descripción |
---|---|
Split() |
Divide una cadena en un array de subcadenas según delimitadores |
Join() |
Une un array de cadenas insertando un separador entre ellas |
Opciones del método Split:
Opción | Descripción |
---|---|
StringSplitOptions.None |
Comportamiento predeterminado (mantiene entradas vacías) |
StringSplitOptions.RemoveEmptyEntries |
Elimina elementos vacíos del resultado |
string listaNombres = "Juan,María,Pedro,Ana,Luis";
// División en un array de cadenas
string[] nombres = listaNombres.Split(',');
Console.WriteLine("Lista de nombres:");
foreach (string nombre in nombres)
{
Console.WriteLine($"- {nombre}");
}
// Unión de cadenas
string[] palabras = { "Hola", "a", "todos", "los", "programadores" };
string mensajeUnido = string.Join(" ", palabras);
Console.WriteLine($"Mensaje unido: {mensajeUnido}");
// División con varias opciones
string textoConSeparadores = "uno,dos;tres.cuatro|cinco";
string[] partes = textoConSeparadores.Split(new char[] { ',', ';', '.', '|' });
Console.WriteLine("Partes separadas:");
foreach (string parte in partes)
{
Console.WriteLine($"- {parte}");
}
Interpolación y formato de cadenas
C# ofrece diversas técnicas para dar formato a las cadenas, incluyendo especificadores de formato y alineación:
Técnica | Descripción |
---|---|
Interpolación ($"..." ) |
Permite incluir expresiones dentro de cadenas |
String.Format() |
Método tradicional para formatear cadenas |
Especificadores de formato | Códigos como :C (moneda), :D (decimal), :F (punto fijo) |
Alineación | Especificar ancho y alineación con {0,-10} (alineación a izquierda) o {0,10} (alineación a derecha) |
Especificadores de formato comunes:
Especificador | Descripción | Ejemplo |
---|---|---|
C |
Formato de moneda | 1234.56 → $1,234.56 |
D |
Entero decimal | 123 → 123 |
E |
Notación científica | 12345 → 1.234500E+004 |
F |
Punto fijo | 12.34 → 12.34 |
N |
Numérico con separadores | 1234.56 → 1,234.56 |
P |
Porcentaje | 0.1234 → 12.34% |
X |
Hexadecimal | 255 → FF |
yyyy-MM-dd |
Fecha personalizada | DateTime.Now → 2023-11-01 |
// Interpolación simple (C# 6.0+)
string nombreProducto = "Laptop";
decimal precio = 1299.99m;
int unidades = 5;
string infoProducto = $"Producto: {nombreProducto}, Precio: {precio}€, Unidades: {unidades}";
Console.WriteLine(infoProducto);
// Formato de números en interpolación
string precioFormateado = $"El precio total es: {precio * unidades:C2}"; // Formato de moneda con 2 decimales
Console.WriteLine(precioFormateado);
// Método String.Format (versión anterior a la interpolación)
string mensaje = string.Format("Hay {0} unidades de {1} a {2:C}", unidades, nombreProducto, precio);
Console.WriteLine(mensaje);
// Formatos personalizados
double porcentaje = 0.1275;
DateTime fecha = DateTime.Now;
string datosFormateados = $"Porcentaje: {porcentaje:P2}, Fecha: {fecha:dd/MM/yyyy HH:mm}";
Console.WriteLine(datosFormateados);
// Alineación y espaciado
string alineado = $"|{"Izquierda",-15}|{"Centro",10}|{"Derecha",15}|";
Console.WriteLine(alineado);
// Formato condicional
int temperatura = 28;
string mensaje2 = $"La temperatura es {temperatura}°C, {(temperatura > 25 ? "¡hace calor!" : "temperatura normal")}";
Console.WriteLine(mensaje2);
Ejemplo práctico: Procesador de texto simple
Vamos a aplicar los conceptos que hemos aprendido en un ejemplo práctico: un procesador de texto simple que permite realizar diversas operaciones con cadenas.
using System;
using System.Text;
using System.Collections.Generic;
class ProcesadorTexto
{
static void Main()
{
Console.WriteLine("=== PROCESADOR DE TEXTO SIMPLE ===");
Console.WriteLine("Introduce un texto para analizar:");
string texto = Console.ReadLine();
if (string.IsNullOrEmpty(texto))
{
texto = "Este es un texto de ejemplo para analizar si el usuario no introduce nada.";
Console.WriteLine($"Se usará el texto por defecto: {texto}");
}
while (true)
{
Console.WriteLine("\nOperaciones disponibles:");
Console.WriteLine("1. Contar caracteres, palabras y líneas");
Console.WriteLine("2. Convertir a mayúsculas/minúsculas");
Console.WriteLine("3. Buscar y reemplazar texto");
Console.WriteLine("4. Extraer parte del texto");
Console.WriteLine("5. Dividir en palabras");
Console.WriteLine("6. Estadísticas numéricas");
Console.WriteLine("7. Salir");
Console.Write("\nSelecciona una opción (1-7): ");
string opcion = Console.ReadLine();
if (!int.TryParse(opcion, out int opcionNum))
{
Console.WriteLine("Por favor, introduce un número válido.");
continue;
}
switch (opcionNum)
{
case 1:
ContarElementos(texto);
break;
case 2:
ConvertirMayusculasMinusculas(texto);
break;
case 3:
texto = BuscarYReemplazar(texto);
break;
case 4:
ExtraerParteTexto(texto);
break;
case 5:
DividirEnPalabras(texto);
break;
case 6:
EstadisticasNumericas(texto);
break;
case 7:
Console.WriteLine("¡Gracias por usar el procesador de texto!");
return;
default:
Console.WriteLine("Opción no válida. Inténtalo de nuevo.");
break;
}
}
}
static void ContarElementos(string texto)
{
// Contar caracteres
int caracteresTotal = texto.Length;
int caracteresSinEspacios = texto.Replace(" ", "").Length;
// Contar palabras
string[] palabras = texto.Split(new char[] { ' ', '\n', '\t', '.', ',', ';', ':', '!', '?' },
StringSplitOptions.RemoveEmptyEntries);
int numeroPalabras = palabras.Length;
// Contar líneas
string[] lineas = texto.Split(new char[] { '\n' }, StringSplitOptions.None);
int numeroLineas = lineas.Length;
Console.WriteLine($"\nEstadísticas del texto:");
Console.WriteLine($"- Total de caracteres: {caracteresTotal}");
Console.WriteLine($"- Caracteres sin espacios: {caracteresSinEspacios}");
Console.WriteLine($"- Número de palabras: {numeroPalabras}");
Console.WriteLine($"- Número de líneas: {numeroLineas}");
}
static void ConvertirMayusculasMinusculas(string texto)
{
Console.WriteLine("\n1. Convertir a MAYÚSCULAS");
Console.WriteLine("2. Convertir a minúsculas");
Console.WriteLine("3. Convertir Primera Letra De Cada Palabra A Mayúscula");
Console.Write("Selecciona una opción (1-3): ");
if (int.TryParse(Console.ReadLine(), out int opcion))
{
switch (opcion)
{
case 1:
Console.WriteLine($"\nTexto en MAYÚSCULAS:\n{texto.ToUpper()}");
break;
case 2:
Console.WriteLine($"\nTexto en minúsculas:\n{texto.ToLower()}");
break;
case 3:
// Convertir primera letra de cada palabra a mayúscula
StringBuilder sb = new StringBuilder();
bool nuevaPalabra = true;
foreach (char c in texto)
{
if (char.IsWhiteSpace(c))
{
nuevaPalabra = true;
sb.Append(c);
}
else if (nuevaPalabra)
{
sb.Append(char.ToUpper(c));
nuevaPalabra = false;
}
else
{
sb.Append(char.ToLower(c));
}
}
Console.WriteLine($"\nTexto con primeras letras en mayúscula:\n{sb.ToString()}");
break;
default:
Console.WriteLine("Opción no válida.");
break;
}
}
else
{
Console.WriteLine("Por favor, introduce un número válido.");
}
}
static string BuscarYReemplazar(string texto)
{
Console.Write("\nIntroduce el texto a buscar: ");
string buscar = Console.ReadLine();
if (string.IsNullOrEmpty(buscar))
{
Console.WriteLine("No se ha introducido texto para buscar.");
return texto;
}
int ocurrencias = 0;
int indice = texto.IndexOf(buscar);
while (indice != -1)
{
ocurrencias++;
indice = texto.IndexOf(buscar, indice + 1);
}
Console.WriteLine($"Se encontraron {ocurrencias} ocurrencias de '{buscar}'");
if (ocurrencias > 0)
{
Console.Write("¿Deseas reemplazar este texto? (S/N): ");
string respuesta = Console.ReadLine();
if (respuesta.ToUpper() == "S")
{
Console.Write("Introduce el texto de reemplazo: ");
string reemplazo = Console.ReadLine();
string nuevoTexto = texto.Replace(buscar, reemplazo);
Console.WriteLine("\nTexto modificado:");
Console.WriteLine(nuevoTexto);
return nuevoTexto;
}
}
return texto;
}
static void ExtraerParteTexto(string texto)
{
Console.WriteLine($"\nLongitud total del texto: {texto.Length} caracteres");
Console.Write("Introduce la posición inicial (0-" + (texto.Length - 1) + "): ");
if (!int.TryParse(Console.ReadLine(), out int inicio) || inicio < 0 || inicio >= texto.Length)
{
Console.WriteLine("Posición inicial no válida.");
return;
}
Console.Write("Introduce la longitud a extraer: ");
if (!int.TryParse(Console.ReadLine(), out int longitud) || longitud <= 0)
{
Console.WriteLine("Longitud no válida.");
return;
}
// Ajustar la longitud si excede el tamaño del texto
if (inicio + longitud > texto.Length)
{
longitud = texto.Length - inicio;
Console.WriteLine($"Se ajustó la longitud a {longitud} para no exceder el texto.");
}
string textoExtraido = texto.Substring(inicio, longitud);
Console.WriteLine("\nTexto extraído:");
Console.WriteLine(textoExtraido);
}
static void DividirEnPalabras(string texto)
{
// Dividir por espacios y signos de puntuación comunes
string[] palabras = texto.Split(new char[] { ' ', '\n', '\t', '.', ',', ';', ':', '!', '?' },
StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine($"\nSe encontraron {palabras.Length} palabras:");
// Mostrar las primeras 20 palabras o todas si hay menos
int mostrar = Math.Min(20, palabras.Length);
for (int i = 0; i < mostrar; i++)
{
Console.WriteLine($"{i+1}. {palabras[i]}");
}
if (palabras.Length > 20)
{
Console.WriteLine($"... y {palabras.Length - 20} palabras más.");
}
// Opción para ver las palabras más largas
Console.Write("\n¿Quieres ver las 5 palabras más largas? (S/N): ");
if (Console.ReadLine().ToUpper() == "S")
{
// Ordenar las palabras por longitud (de mayor a menor)
Array.Sort(palabras, (a, b) => b.Length.CompareTo(a.Length));
Console.WriteLine("\nLas 5 palabras más largas son:");
int maxPalabras = Math.Min(5, palabras.Length);
for (int i = 0; i < maxPalabras; i++)
{
Console.WriteLine($"{i+1}. {palabras[i]} ({palabras[i].Length} caracteres)");
}
}
}
static void EstadisticasNumericas(string texto)
{
Console.WriteLine("\nBuscando números en el texto...");
// Dividir el texto y buscar elementos que parezcan números
string[] elementos = texto.Split(new char[] { ' ', '\n', '\t', '.', ',', ';', ':', '!', '?' },
StringSplitOptions.RemoveEmptyEntries);
List<double> numeros = new List<double>();
foreach (string elemento in elementos)
{
// Intentar convertir a número
if (double.TryParse(elemento, out double numero))
{
numeros.Add(numero);
Console.WriteLine($"Encontrado número: {numero}");
}
}
if (numeros.Count > 0)
{
// Calcular estadísticas
double suma = 0;
double min = numeros[0];
double max = numeros[0];
foreach (double num in numeros)
{
suma += num;
min = Math.Min(min, num);
max = Math.Max(max, num);
}
double promedio = suma / numeros.Count;
Console.WriteLine($"\nEstadísticas de los {numeros.Count} números encontrados:");
Console.WriteLine($"- Suma: {suma}");
Console.WriteLine($"- Promedio: {promedio:F2}");
Console.WriteLine($"- Mínimo: {min}");
Console.WriteLine($"- Máximo: {max}");
}
else
{
Console.WriteLine("No se encontraron números en el texto.");
}
}
}
Resumen
En este artículo, hemos explorado dos temas fundamentales en la programación con C#: la conversión de tipos y las operaciones con cadenas de texto. Hemos visto cómo C# proporciona diferentes mecanismos para convertir datos entre distintos tipos, desde conversiones implícitas y explícitas hasta métodos más especializados como `Parse`, `TryParse` y la clase `Convert`. Estas herramientas nos permiten adaptar los datos según nuestras necesidades, siempre teniendo en cuenta los posibles riesgos como la pérdida de precisión o los desbordamientos.
Por otro lado, hemos profundizado en las numerosas operaciones disponibles para manipular cadenas de texto, desde la creación y concatenación hasta la búsqueda, extracción, reemplazo y formato. El ejemplo práctico del procesador de texto nos ha mostrado cómo aplicar estos conceptos en una aplicación real, combinando conversiones de tipos y manipulación de cadenas para analizar y transformar texto. Estos conocimientos son esenciales para el desarrollo de aplicaciones en C#, ya que la manipulación de diferentes tipos de datos y el procesamiento de texto son tareas cotidianas en la programación.