En Dart, un String no es simplemente una cadena de texto, sino una secuencia inmutable de unidades de código UTF-16. Esto significa que cuando aplicas un método como toUpperCase() o replaceAll(), no estás modificando la cadena original; en su lugar, Dart crea un nuevo objeto String con los cambios aplicados. Esta inmutabilidad es una decisión de diseño fundamental que garantiza que, si pasas un texto a una función asíncrona, ese valor no cambiará inesperadamente mientras la función se ejecuta.
Para trabajar con texto de forma profesional, debes entender estos cuatro pilares:
- ¿Qué es esto? Son un conjunto de métodos integrados que permiten inspeccionar (buscar), extraer fragmentos, transformar caracteres o dividir una cadena en partes más pequeñas.
- ¿Por qué funciona así? Gracias a la inmutabilidad, el manejo de memoria es más seguro y predecible, evitando efectos secundarios en aplicaciones complejas.
- ¿Cuándo usarlo? Siempre que necesites limpiar la entrada de un usuario (usando
trim()), validar formatos (usandostartsWithoendsWith), o procesar archivos de texto plano (usandosplit). - ¿Qué rompe si lo haces mal? Intentar acceder a un índice que no existe mediante
substring()ocodeUnitAt()lanzará un error de tipoRangeError, lo que detendrá la ejecución de tu programa si no se maneja.
void main() {
// Simulamos una entrada de datos desordenada proveniente de un archivo o usuario
String rawData = " ID_USER_99_ACTIVE ";
// 1. Limpieza: eliminamos espacios en blanco accidentales
String cleanData = rawData.trim();
print('Dato limpio: "$cleanData"');
// 2. Búsqueda: verificamos si contiene patrones específicos
bool isId = cleanData.startsWith("ID_");
bool isActive = cleanData.contains("ACTIVE");
int firstUnderscore = cleanData.indexOf("_");
print('¿Es un ID?: $isId, ¿Está activo?: $isActive, Posición de "_": $firstUnderscore');
// 3. Transformación y Reemplazo: modificamos el contenido
String upperData = cleanData.toUpperCase();
String replacedData = cleanData.replaceFirst("USER", "CLIENT");
print('En mayúsculas: $upperData');
print('Reemplazo: $replacedData');
// 4. Extracción y División: segmentamos la información
// Usamos split para convertir el string en una lista separada por guiones bajos
List<String> parts = cleanData.split('_');
// Accedemos por índice y extraemos una subcadena
String username = parts[1]; // "USER"
String idPart = parts[2]; // "99"
String slice = cleanData.substring(3, 7); // Extrae desde el índice 3 hasta el 6
print('Partes detectadas: $parts');
print('Username: $username, ID: $idPart, Fragmento: $slice');
// 5. Formateo y Comparación
// Rellenamos con ceros a la izquierda para que tenga 5 caracteres
String paddedId = idPart.padLeft(5, '0');
// Comparación lexicográfica (orden alfabético)
int comparison = "Mundo".compareTo("Mundo"); // Retorna 0 si son iguales
// Crear un string desde códigos numéricos (UTF-16)
String fromCodes = String.fromCharCodes([65, 66, 67]); // Retorna "ABC"
print('ID formateado: $paddedId');
print('Comparación: $comparison');
print('Desde códigos: $fromCodes');
}
Análisis del código
Al ejecutar este programa, observarás cómo cada paso genera una nueva cadena. Fíjate en cleanData.trim(): la variable rawData sigue teniendo los espacios originales; solo cleanData es la versión limpia.
Cuando usamos split('_'), Dart escanea la cadena y, cada vez que encuentra el carácter _, corta la secuencia y la guarda en una List<String>. Esto es extremadamente eficiente para procesar formatos como CSV.
En el caso de substring(3, 7), es vital recordar que el segundo parámetro es el límite exclusivo; es decir, se toma hasta el índice 6, pero no el 7. Si intentaras usar un índice superior al largo de la cadena, el programa lanzaría el RangeError mencionado anteriormente.
Para el formateo, padLeft(5, '0') es una herramienta esencial en sistemas de backend donde los IDs deben tener una longitud fija (como 00099), asegurando que las comparaciones de longitud sean consistentes. Finalmente, String.fromCharCodes te permite construir texto a partir de valores numéricos, algo útil cuando trabajas con protocolos de red o procesamiento de archivos binarios.
El error frecuente
Un error común al trabajar con strings es confiar en que un índice existe sin verificar primero su longitud o usar substring con cálculos manuales de índices que pueden salirse de rango.
void main() {
String texto = "Dart";
// ERROR: Intentar acceder a un índice que no existe con substring
// El índice 10 está muy fuera del rango (0-3)
try {
print(texto.substring(0, 10));
} catch (e) {
print('Error detectado: $e'); // Lanza un RangeError
}
// ERROR: Intentar usar una posición que no existe con codeUnitAt
print(texto.codeUnitAt(10));
}
Para evitar esto, siempre valida la longitud de la cadena con length antes de realizar cortes complejos o utiliza el operador [] para acceder a caracteres individuales, ya que es más seguro en ciertos contextos, aunque siempre es mejor verificar el rango.
N° 38