sábado, 28 de mayo de 2022

Curso avanzado de C#. Manipulación de cadenas I

Las cadenas son diferentes de otros tipos de datos. Los programas generalmente las tratan como si fueran cualquier otro dato de tipo valor, pero detrás hay una clase cadena que es notablemente compleja. Podemos ignorar esta complejidad en la mayoría de la programación diaria, pero es importante comprender cómo funcionan las cadenas para que poder manejar situaciones especiales cuando surjan. 

Por ejemplo, si comprendemos cómo se almacenan las cadenas, sabremos cuándo sería mejor utilizar la clase StringBuilder en lugar de concatenarlas. 

Curso avanzado de C#. Manipulación de cadenas I


Nota: 

En C#, palabra clave string es un alias de System.String, por lo que cuando creamos una variable de tipo string, en realidad estamos creando un objeto String. Estilísticamente, la mayoría de los programadores de C# prefieren usar string, pero aquí utilizaremos String para enfatizar que son objetos y no los tipos de valores simples que pueden parecer. 

Detrás de las cadenas 

.NET representa los caracteres como la versión Unicode UTF-16, un formato que usa 16 bits para almacenar cada carácter. Eso permite que un carácter Unicode represente muchos más caracteres de los que se proporcionan en un teclado estándar. (La última versión de Unicode define valores para más de 110.000 caracteres en más de 100 scripts). Una cadena es un objeto que usa una serie de caracteres Unicode para representar un texto. Una de las características más inusuales de los objetos String es que son inmutables. Eso significa que el contenido de una cadena no se puede cambiar después de que se haya creado la cadena. En cambio, los métodos que parecen modificar el valor de una cadena, como Replace y ToUpper, en realidad devuelven un nuevo objeto String que contiene el valor modificado. 

Para conservar memoria, el CLR mantiene una tabla llamada grupo interno (intern pool) que contiene una única referencia a cada valor de texto único utilizado por el programa. Cualquier variable de cadena que se refiera a un texto en particular es en realidad una referencia a un grupo de internos. Varias cadenas que representan el mismo valor se refieren a la misma entrada en el grupo de internos. 

Todo esto requiere algo de sobrecarga, por lo que trabajar con cadenas no es tan rápido como trabajar con tipos de valor. Si un programa debe realizar una gran cantidad de concatenaciones, cada una crea una nueva instancia de String que debe ser internada (añadida al grupo de internos o intern pool) y eso lleva tiempo. En ese caso, el uso de la clase StringBuilder puede ofrecer un mejor rendimiento. 

Constructores de String 

Tres de las formas más comunes de inicializar una variable de cadena son: 

-Establecerla igual a un literal de cadena.

-Establecerla igual al texto introducido por el usuario en un control como un TextBox o ComboBox. 

-Establecerla igual al resultado de un cálculo de cadena. 

El último de estos incluye métodos que formatean una variable para producir un String, como usar el método ToString o el método String.Format. 

Además de estos métodos, la clase String proporciona varios constructores que a veces pueden ser útiles: 

-Un constructor inicializa String a partir de una matriz de caracteres char.

 -Un segundo constructor usa solo parte de una matriz de caracteres, tomando como parámetros la matriz, una posición de inicio y la longitud de los caracteres a usar. 

-Un tercer constructor toma como parámetro un carácter y la cantidad de veces que queremos repetir ese carácter en la nueva cadena. Esto puede resultar especialmente útil si queremos aplicar una sangría a una cadena con un cierto número de espacios o caracteres de tabulación. Por ejemplo, el siguiente código muestra los números del 1 al 10 en líneas separadas con cada línea con sangría de cuatro espacios más que la anterior:

For (int i = 1;i <= 10; i++)

{

     String indent = New String(' ', 4 * i);

    Console.WriteLine(indent + i.ToString());

La mayoría de los valores de cadena se crean mediante literales de cadena, texto ingresado por el usuario o resultados de cálculos, pero los constructores de cadenas a veces pueden ser útiles. 

Campos y propiedades de String 

La clase String proporciona solo tres campos y propiedades: Empty, Length  y un indexador de solo lectura. El campo Empty devuelve un objeto que representa una cadena vacía. Podemos utilizar este valor para establecer el valor de una cadena o para ver si una cadena tiene un valor vacío. (Alternativamente, podemos utilizar el literal de cadena vacía " ".) 

La propiedad Length devuelve el número de caracteres de la cadena. El indexador de solo lectura devuelve los caracteres chars de la cadena. Debido a que es un indexador, podemos obtener sus valores agregando

un índice para el nombre de una variable String. Por ejemplo, la instrucción username [4] devuelve el carácter número 4 en la cadena username. 

El indexador es de solo lectura, por lo que no podemos establecer uno de los caracteres de la cadena con una declaración como username [4] = 'x'. Si queremos hacer algo así, tenemos que utilizar los métodos String que se describen en el siguiente epigrafe. 


Si fuera más fácil tratar String como si fuera una matriz de caracteres de lectura / escritura, podemos utilizar el método ToCharArray para convertir String en una matriz (array) de caracteres, manipularlos y luego crear un nuevo String pasando al constructor la matriz modificada. Por ejemplo, el siguiente código utiliza una matriz para hacer que los caracteres de una cadena se alternen entre mayúsculas y minúsculas: 

Char [] caracteres = text.ToCharArray ();

For (int i = 0; i <caracteres .Length; i ++)

     If (i% 2 == 0) caracteres[i] = char.ToUpper ( caracteres[i]);

     Else caracteres[i] = Char.ToLower (caracteres[i]);

text = New string(caracteres);

También podemos utilizar el indexador como fuente de iteración en un bucle foreach:

String texto = "Podemos acercarnos más a la verdad mediante ejemplos negativos que con verificaciones de nuestras creencias.";

int[] conteos = New int[26]; texto = texto.ToUpper ();

foreach (char ch in texto)

{

     If (Char.IsLetter(ch))

     {

         int index = (Int()) ch - (int)'A';

         conteos [index] ++;

     }

} 

Este código crea un objeto String llamado texto. Crea una matriz (array) de conteos para contener los conteos de las 26 letras de la A a la Z utilizadas en la cadena. Antes de procesar la cadena, el código convierte el texto en mayúsculas. 

A continuación, se utiliza una instrucción foreach para recorrer los caracteres de la cadena. Para cada carácter, el código utiliza el método IsLetter de la clase char para decidir si el carácter es una letra y no un espacio o un signo de puntuación. Si el carácter es una letra, el código lo convierte en un número entero y le resta el valor de "A" convertido en un número entero para obtener un índice en la matriz de conteos. La letra A tiene índice 0, B tiene índice 1 y así sucesivamente. Luego, el código incrementa el recuento de ese índice. Cuando finaliza el código, la matriz de conteos contiene el número de veces que aparece cada carácter en la cadena. 

Métodos de String

 La clase String proporciona muchos métodos que nos permiten trabajar con cadenas. La Tabla mostrada a continuación, describe los métodos estáticos más útiles proporcionados por la clase String. Debido a que estos son métodos estáticos, un programa usa la clase String para invocar estos métodos. Por ejemplo, para utilizar el método Compare, el programa utiliza una declaración similar a if (String.Compare (value1, value2)> 0) .... 

 

Método

Descripción

Compare

Compara dos cadenas y devuelve –1, 0 o 1 para indicar si la primera cadena debe considerarse anterior, igual o posterior de la segunda cadena en el orden de clasificación. Versiones sobrecargadas de este método nos permiten especificar reglas de comparación de cadenas, como ignorar mayúsculas y minúsculas, o qué reglas de comparación de cultura utilizar.

Concat

Toma como parámetro una matriz de cadenas u otros objetos y devuelve una cadena que contiene la concatenación de los objetos. Una versión sobrecargada permite pasar cualquier número de argumentos como parámetros y devuelve los argumentos concatenados. (ver también join)

Copy

Devuelve una copia de la cadena (ver también clone en la siguiente tabla)

Equals

Devuelve verdadero si dos cadenas tienen el mismo valor. (Ver también la instancia Equals de la siguiente tabla)

Format

Utiliza una cadena de formato y una serie de objetos para generar una cadena de texto formateada.

IsNullOrEmpty

Devuelve verdadero si String contiene una cadena en blanco "" o la variable de cadena se refiere a nulo. El siguiente código establece dos variables iguales a una cadena vacía y una tercera variable a nula:

 

String value1 = "";

String value2 = String.Empty;

String value3 = null;

 

Existe una diferencia entre una cadena vacía y una nula El método IsNullOrEmpty hace que sea más fácil tratar ambos valores de la misma manera

 

IsNullOrWhiteSpace

Devuelve verdadero si la variable String contiene una cadena en blanco, hace referencia a nulo o solo contiene caracteres de espacio en blanco. Los caracteres de espacio en blanco son los que Char.IsWhiteSpace devuelve verdadero

Join

Une los valores en una matriz (array) de cadenas u otros objetos separados por una cadena de separación. Por ejemplo, el siguiente código establece la variable allDays para contener los días de la semana separados por comas:

 

String[] diasSemana =

{

"Lunes", "Martes", "Miércoles",

"Jueves", "Viernes", "Sabado",

"Domingo"

};

String todosLosDias = String.Join(",", diasSemana);

 


Métodos de Instancia

La siguiente tabla describe los métodos de instancia más útiles proporcionados por la clase String. Debido a que estos son métodos de instancia, un programa debe usar una instancia de la clase String para invocar estos métodos. 

Por ejemplo, para usar el método CompareTo, el programa usaría una declaración similar a if (valor1.CompareTo (valor2)> 0) .... 

Método

Descripción

Clone

Devuelve una nueva referencia a la cadena. El comportamiento es un poco diferente al

Clonar métodos proporcionados por la mayoría de las otras clases porque las cadenas son inmutables.

Para esta clase, la nueva referencia se refiere al mismo valor en el grupo de internos. Como el String original.

CompareTo

Compara la cadena con otra cadena y devuelve –1, 0 o 1 para indicar que esta Cadena debe considerarse antes, igual o después de la otra cadena en el orden de clasificación. Si queremos especificar reglas de comparación de cadenas, ya sea

para ignorar el uso de mayúsculas y minúsculas y qué reglas de comparación de la cultura utilizar, utilizaremos el método

Compare.

Contains

Devuelve verdadero si la cadena contiene una subcadena especificada.

CopyTo

Copia un número específico de caracteres desde una posición de inicio especificada en una matriz (array)  de caracteres.

EndsWith

Devuelve verdadero si la cadena termina con una subcadena especificada.

Versiones sobrecargadas nos permiten especificar el tipo de comparación de cadenas.

Equals

Devuelve verdadero si esta cadena tiene el mismo valor que otra cadena.

IndexOf

Devuelve el índice de la primera aparición de un carácter o subcadena dentro de

una cadena. Los parámetros permiten especificar la posición en la cadena donde la búsqueda debe comenzar y terminar, y las opciones de comparación de cadenas.

IndexOfAny

Devuelve el índice de la primera aparición de cualquier carácter en una matriz dentro de la cadena. Los parámetros permiten especificar la posición en la Cadena donde  debe comenzar y terminar la búsqueda.

Insert

Inserta una cadena en una posición específica dentro de esta cadena y devuelve el resultado.

LastIndexOf

Devuelve el índice de la última aparición de un carácter o subcadena dentro de una cadena. Los parámetros permiten especificar la posición en la cadena donde debe comenzar y finalizar la búsqueda, y las opciones de comparación.

LastIndexOfAny

Devuelve el índice de la última aparición de cualquier carácter en una matriz dentro de la cadena. Los parámetros permiten especificar la posición en la cadena donde debe comenzar y terminar la búsqueda.

PadLeft

Devuelve la cadena rellenada a una cierta longitud agregando espacios o un carácter especificado a la izquierda. Esto facilita la alineación del texto en columnas con un ancho de fuente fija.

PadRight

Devuelve la Cadena rellenada a una cierta longitud agregando espacios o un carácter especificado a la derecha. Esto facilita la alineación del texto en columnas con un ancho de fuente fija.

Remove

Elimina los caracteres que comienzan en una posición especificada o al final de la

cadena o para un cierto número de caracteres y devuelve el resultado.

Replace

Reemplaza todas las instancias de un carácter o cadena con otro carácter o cadena y devuelve el resultado.

Split

Devuelve una matriz que contiene trozos de cadena delimitados por caracteres. Las versiones sobrecargadas permiten indicar el número máximo de trozos a devolver y dividir opciones, como eliminar entradas vacías. por ejemplo, el siguiente código divide una serie de números separados por comas y guiones, eliminando cualquier entrada que esté vacía:

 

Char[] delimitadores = { ',', '-' };

String valores = "14-63,,27-87,565";

String[]campos = valores.Split(delimitadores,

StringSplitOptions.RemoveEmptyEntries);

StartsWith

Devuelve verdadero si la cadena comienza con una subcadena especificada. Versiones sobrecargadas  permiten especificar el tipo de comparación, si ignorar el caso o el tipo.

Substring

Devuelve una nueva cadena que contiene una subcadena de esta cadena especificada por un inicio de posición y su longitud.

ToCharArray

Devuelve una matriz de caracteres que representa algunos o todos los caracteres de la cadena.

ToLower

Devuelve una copia de la cadena convertida a minúsculas.

ToString

Devuelve la cadena. Normalmente, no necesitamos hacer esto, pero si estamos tratando String como un objeto, por ejemplo, si está en una lista o matriz de objetos, es útil saber que este objeto tiene un método ToString.

ToUpper

Devuelve una copia de la cadena convertida a mayúsculas.

Trim

Devuelve una copia de la cadena a la que se le han eliminado espacios en blanco iniciales y finales. Una versión sobrecargada permite especificar qué caracteres deben ser eliminados.

TrimEnd

Devuelve una copia de la cadena con los espacios en blanco finales eliminados

TrimStart

Devuelve una copia de la cadena con los espacios en blanco iniciales eliminados.

Los métodos de la clase String permiten que un programa realice todo tipo de manipulaciones de cadenas, como analizar la entrada del usuario para obtener las partes de una dirección, un número de teléfono u otras partes de información formateada. 

Ejemplo práctico

Modificaremos el formulario de pedidos que creamos en esta entrada  para que que nos permita manejar el porcentaje de IVA especificado. Ahora si el valor introducido por el usuario contiene un carácter %, parseamos el valor y lo dividimos entre 100. 

El método decimal.TryParse no puede analizar (parsear)  una cadena que contenga el carácter %. Para analizar el valor, el programa debemos eliminar el carácter % si está presente, utilizaremos TryParse para convertir el resultado en un valor decimal y luego dividir entre 100 si el texto original contenía el carácter %. El siguiente código muestra como podemos hacer esto:

// Recogemos el IVA como cadena

String strIVA = txtIVA.Text;

// Eliminamos el caracter % si existe.

strIVA = strIVA.Replace("%", "");

// Parseamos el IVA.

Decimal decIVA;

If (!decimal.TryParse(strIVA, out decIVA))

{

     DisplayErrorMessage(

     "Formato no válido. El IVA debe ser un valor decimal.",

     "Formato no válido", txtIVA);

     Return;

}

// Si la cadena contiene el carácter %, dividimos entre 100.

If (txtIVA .Text.Contains("%")) decIVA /= 100;

 

No hay comentarios:

Publicar un comentario