miércoles, 23 de abril de 2014

Receta No. 2-1 en C#: Manipular el Contenido de una Cadena Texto Eficientemente

Tabla de Contenido

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
4. Práctica: Código Fuente C#
4.1 Asignación de memoria de un objeto StringBuilder
4.2 Invertir cadena de caracteres
5. Conclusiones
6. Glosario
7. Enlaces & Literatura

0. Introducción

Bien sabemos que el estado natural o la representación más primitiva de los datos corresponde con cadenas de texto que pueden adquirir diferente significado según su contexto o representación: numérico (útil para las operaciones aritméticas, e.g.), fecha (determinar la edad de una persona por medio de la diferencia), texto (un párrafo de un libro), &c. Los programadores lidian en su día a día de sus profesiones tratando con cadenas de texto que deben ser tratadas de una u otra manera para alcanzar el objetivo del sistema informático que esté construyendo. Hacer uso eficiente de las construcciones del lenguaje es de importante cuidado, pues sabemos que hay límites impuestos por la capacidad de cómputo del sistema en el que se ejecutará la aplicación a desarrollar. En esta receta vamos a conocer un recurso (tipo) del Framework .NET para manipular eficientemente cadenas de texto. ¡Manos a la obra!

1. Problema

La manipulación de texto sobre tipos de datos string [3] puede crearnos problemas en el uso de la memoria stack (espacio de memoria para el almacenamiento de data de objetos) -cfr. Variables y Parámetros en C# - Parte 1-. Tenemos que atacar este problema de inmutabilidad de string [2] utilizando un tipo alternativo para hacer uso eficiente de la memoria.

2. Solución

El Framework .NET cuenta con una clase óptimamente diseñada para constuir cadenas de texto a través de manipulaciones programáticas (vía los métodos de su implementación). El nombre de clase completamente calificado (FQCN [4]):

System.Text.StringBuilder [2]

3. Discusión de la Solución

La clase string (alias de String) posee la misma característica de los tipos primitivos (o integrados), es decir los tipos numéricos: la de inmutabilidad. Se dice que una cadena de texto es inmutable porque su contenido (una vez creada) no puede ser modificado, en su lugar (e.g., cuando realizamos una concatenación de texto, como: "Hola" + "Mundo", estamos creando una nueva cadena a partir de las dos anteriores: "HolaMundo") se crea un nuevo tipo en la memoria stack de la CLR.

Veamos lo anterior con un ejemplo de código C# más completo:

// Primera cadena
// la variable nombreCompleto hace referencia al objeto con data "John"
String nombreCompleto = "John";

// Cuenta de objetos string en el stack: 1

// Proceso de concatenación
nombreCompleto = nombreCompleto + " Ortiz";

// Hasta este punto la variable nombreCompleto ahora apunta al objeto string
// con data "John Ortiz".

// Cuenta de objetos string en el stack: 2

La clase StringBuilder nos salva el día. Esta clase trabaja con un buffer de datos [4] que permite la manipulación de una cadena de texto; esto facilita y permite que en tiempo de ejecución se evite la creación de nuevos tipos string en la memoria stack: cada cada cambio sobre el contenido de la cadena mantendrá una única copia. Visto esto, ganamos eficiencia en el uso de los recursos de memoria y nuestra aplicación será más estable en ambientes de producción rígidos y exigentes.

Miremos cómo se compartaría (de forma análoga) el fragmento de código previo pero con StringBuilder:

// la variable nombreCompleto hace referencia al objeto StringBuilder con data "John"
System.Text.StringBuilder nombreCompleto = new System.Text.StringBuilder("John");

// Cuenta de objetos string en el stack: 1

// Proceso de 'adición' de cadeanas
nombreCompleto.Append(" Ortiz");

// El contenido de nombreCompleto: nombreCompleto.ToString() -> "John Ortiz"
// Cuenta de objetos string en el stack: 1

Algunas consideraciones importantes acerca del uso de objetos StringBuilder, en particular cuando adicionamos nuevos caracteres a la cadena:

  • Capacity [6]: Esta propiedad corresponde con la capacidad del buffer (es decir, el número de caracteres) que puede contener un objeto StringBuilder en tiempo de ejecución). La capacidad inicial es de 16 caracteres. La capacidad se duplica cuando la CLR detecta la superación de la capacidad actual.

    Desde [1] nos aconsejan tener cuidado con la manipulación de cadenas en este tipo de objetos, pues podríamos hacer que se pierdan las bondades al no manejar correctamente la capacidad a medida que añadimos bloques o caracteres individuales.
  • Length [7]: Corresponde con la cantidad de caracteres de la cadena localizada en el objeto StringBuilder.
Otras consideraciones adicionales a tener en cuenta:
  • Al establecer la propiedad Capacity con una capacidad inferior a la de Length, la primera lanza la excepción: System.ArgumentOutOfRangeException.

    La capacidad máxima de un objeto
    StringBuilder alcanza los 2 gigabytes.
  • Si establecemos un valor inferior a la longitud actual -propiedad Length- de la cadena en el objeto StringBuilder, entonces su contenido es truncado al nuevo valor inferior al actual.
  • Al establecer un valor superior al de la propiedad Length, el buffer llena esos espacios vacíos con caracteres de espacio.
[Nota: Recomiendo ver el ejemplo enunciado en [8] para comprender la diferencia entre los tipos string y StringBuilder.]

4. Práctica: Código Fuente C#

Empecemos con esta sección práctica para comprender más interiormente esta clase tan útil para nuestros desarrollos donde la manipulación de cadenas de texto es un requisito ineludible.

4.1 Asignación de memoria de un objeto StringBuilder

Este primer ejemplo es una adaptación del hallado en [2].

Vamos a observar cómo un objeto StringBuiler localiza (asigna) memoria de forma dinámica: ampliando su capacidad según es necesario.


En las líneas 26-36 se declara la función AsignacionMemoriaStringBuilder que permite conocer el estado actual de varias de las propiedades del objeto StringBuilder en tiempo de ejecución (usando Reflection -en futuro próximo hablaré más acerca de este tema-). Esta función es llamada cada vez que se adiciona texto a la instancia objSB (de tipo StringBuilder).

Compilación:


  1. csc /target:exe /out:AsignacionMemoriaStringBuilder.exe AsignacionMemoriaStringBuilder.cs

Ejecución:
Ejecución del archivo AsignacionMemoriaStringBuilder.exe
Figura 1. Ejecución del archivo AsignacionMemoriaStringBuilder.exe.

4.2 Invertir Cadena de Caracteres

Con este ejemplo vamos a aprender cómo hacer uso eficiente de la manipulación de cadenas de caracteres a través de StringBuilder.


En las líneas 24-44 se declara y se implementa el método InvertirCadena para invertir los letras de una cadena de caracteres. Observemos que esto ofrece una ventaja: el objeto StringBuilder que se crea en la línea 34 -cadenaInversa- empieza con una capacidad inicial equivalente a la longitud del objeto string -cadena-.

Compilación:


  1. csc /target:exe /out:ManipulacionCadenas.exe ManipulacionCadenas.cs

> Prueba de ejecución.

Conclusiones

Comprendimos con esta receta que la clase StringBuilder nos ofrece una composición lógica para la creación de cadenas de caracteres, pero sobretodo, la manipulación de cadenas de caracteres en tiempo de ejecución de forma más eficiente y natural.

Glosario

  • Buffer
  • Cadena de texto
  • CLR
  • Nombre completamente calificado
  • Stack

Enlaces & Literatura

[1]: Visual C# 2010 Recipes by Allen Jones and Adam Freeman. Copyright 2010 Allen Jones and Adam Freeman, 978-1-4302-2525-6.

[3]: string (C# Reference) - http://msdn.microsoft.com/en-us/library/362314fe.aspx
[4]: Data buffer - Wikipedia, the free encyclopedia - http://en.wikipedia.org/wiki/Data_buffer
[5]: StringBuilder.Capacity Property (System.Text) - http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.capacity%28v=vs.110%29.aspx
[6]: StringBuilder.Length Property (System.Text) - http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.length%28v=vs.110%29.aspx
[7]: ArgumentOutOfRangeException Class (System) - http://msdn.microsoft.com/en-us/library/system.argumentoutofrangeexception%28v=vs.110%29.aspx
[8]: The String and StringBuffer types - http://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=vs.110).aspx#StringAndSB


M

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.