Validación de datos en el sistema de inventario de
KD-Electronics usando regex
con java.util.regex
Cuando empecé a investigar este tema me di cuenta de que una expresión regular (o regex) es básicamente un patrón escrito que le dice al programa cómo debe verse un texto para considerarse como válido. Con el mismo patrón puedo validar una entrada, buscar coincidencias dentro de un texto largo o reemplazar partes específicas. Al principio los símbolos pueden parecer confusos, pero después de explorar por un rato con ejemplos pequeños la lógica se vuelve bastante intuitiva.
En Java todo esto vive dentro del paquete
java.util.regex, que existe desde Java 1.4. Las dos
clases que hay que manipular son Pattern y
Matcher, aunque si uno quiere validar de manera rápida
está el atajo String.matches(). La documentación
oficial describe a Pattern como «una representación compilada de una expresión regular. Una
expresión regular, especificada como cadena de texto, debe primero
compilarse en una instancia de esta clase» (Oracle, 2024). En términos sencillos: Pattern es la
regla ya traducida a algo que la JVM (Java Virtual Machine) entiende bien, y
Matcher es el que se encarga de aplicarla sobre el
texto que sea que yo le pase.
// Forma rápida con String.matches()
String texto = "Hola123";
boolean resultado = texto.matches("[A-Za-z0-9]+");
System.out.println(resultado); // true
// Forma reutilizable con Pattern y Matcher
Pattern p = Pattern.compile("[A-Za-z0-9]+");
Matcher m = p.matcher(texto);
System.out.println(m.matches()); // true
Uno de los aspectos que más me llamó la atención mientras investigaba es que las
expresiones regulares tienen muchas aplicaciones, por ejemplo: validando
formularios, revisando archivos de texto, leyendo logs,
transformando datos o incluso en la búsqueda avanzada en editores de código. No son una herramienta pensada para un solo problema,
y esa versatilidad fue lo que vi beneficioso para usarlas
en el proyecto de KD-Electronics. Además, si tenemos en cuenta el rendimiento, la propia Oracle deja un consejo:
«si un patrón va a usarse múltiples veces, compilarlo una vez y
reutilizarlo será más eficiente que invocar este método cada
vez» (Oracle, 2024). Básicamente, compilar una sola vez con
Pattern.compile() y guardar ese objeto es mucho mejor
que estar llamando String.matches() en cada validación.
Un solo patrón define exactamente qué formato es aceptable, sin ambigüedades ni condicionales anidados.
El mismo patrón compilado con Pattern.compile() se
aplica cuantas veces sea necesario sin recosto adicional.
La JVM procesa patrones compilados de forma eficiente, mucho más
rápido que cadenas de if/else equivalentes.
Se adaptan a prácticamente cualquier formato: fechas, correos, códigos de producto, precios decimales y más.
Aplicándolo al caso de KD-Electronics pude entender el por qué la calidad de los datos importa tanto en un sistema de inventario. Si alguien mete un código mal escrito, un precio con formato raro o una categoría con caracteres que no deberían estar ahí, eso puede dañar reportes, tronar integraciones externas o dejar la base de datos llena de basura difícil de limpiar después. Es por eso veo las regex como una especie de guardia de segurida, ya que antes de que el dato llegue siquiera a la capa de negocio, éste decide si entra o se devuelve con un error claro.
| Ventaja | Descripción | Ejemplo en inventario |
|---|---|---|
| Precisión | Define exactamente qué es válido |
El código de producto debe iniciar con KD-
|
| Consistencia | Mismas reglas en toda la aplicación | Precios siempre en formato numérico positivo |
| Mantenibilidad | Cambiar una regex actualiza toda la validación | Modificar la longitud del código en un solo lugar |
| Legibilidad | Reemplaza bloques de if/else extensos | Validar precio en 1 línea vs 10+ condicionales |
| Seguridad | Previene inyecciones y datos maliciosos | Rechazar caracteres especiales en nombres |
KD-Electronics requiere un módulo CRUD de productos con los campos: código de producto, nombre, descripción, precio base, precio de venta, categoría y cantidad disponible. El delete es lógico (no físico) y el read filtra por código de producto.
A continuación se presentan cada campo con su regla de negocio, la expresión regular correspondiente y su implementación en Java.
📌 Regla: Prefijo KD- seguido de 4 a 8 caracteres
alfanuméricos en mayúscula. Inmutable: no se modifica tras la
creación.
String codigo = "KD-ELEC001";
boolean valido = codigo.matches("^KD-[A-Z0-9]{4,8}$");
System.out.println(valido); // true
📌 Regla: Letras (con tildes y ñ), espacios, entre 3 y 100 caracteres. Sin números ni caracteres especiales.
String nombre = "Televisor Samsung";
boolean valido = nombre.matches("^[A-Za-záéíóúÁÉÍÓÚñÑ\\s]{3,100}$");
System.out.println(valido); // true
📌 Regla: Texto libre (cualquier carácter, incluyendo saltos de línea), mínimo 10 y máximo 500 caracteres.
String desc = "Televisor QLED 55 pulgadas con resolución 4K";
boolean valido = desc.matches("^[\\s\\S]{10,500}$");
System.out.println(valido); // true
. en Java no captura saltos de línea por
defecto. Se usa [\s\S] para abarcar cualquier
carácter, incluyendo \n.
📌 Regla: Número decimal positivo mayor que cero. Máximo 2 decimales opcionales. No admite negativos ni cero.
String precioBase = "1500000.99";
boolean valido = precioBase.matches("^[1-9]\\d*(\\.\\d{1,2})?$");
System.out.println(valido); // true
📌 Regla: Idéntica al precio base. Número decimal positivo mayor que cero, hasta 2 decimales.
String precioVenta = "1750000";
boolean valido = precioVenta.matches("^[1-9]\\d*(\\.\\d{1,2})?$");
System.out.println(valido); // true
📌 Regla: Solo letras (con tildes y ñ) y espacios. Entre 3 y 50 caracteres.
String categoria = "Electrodomésticos";
boolean valido = categoria.matches("^[A-Za-záéíóúÁÉÍÓÚñÑ\\s]{3,50}$");
System.out.println(valido); // true
📌 Regla: Número entero mayor o igual a cero. No admite decimales ni negativos.
String cantidad = "250";
boolean valido = cantidad.matches("^\\d+$");
System.out.println(valido); // true
Para cerrar, junté todas las expresiones regulares en una sola
clase ValidadorProducto. Así cada campo del CRUD
tiene su propio método y puedo llamarlos desde cualquier parte
del proyecto sin repetir el patrón.
// Ejemplo completo: validar todos los campos del producto
public class ValidadorProducto {
private static final String REGEX_CODIGO = "^KD-[A-Z0-9]{4,8}$";
private static final String REGEX_NOMBRE = "^[A-Za-záéíóúÁÉÍÓÚñÑ\\s]{3,100}$";
private static final String REGEX_DESC = "^[\\s\\S]{10,500}$";
private static final String REGEX_PRECIO = "^[1-9]\\d*(\\.\\d{1,2})?$";
private static final String REGEX_CATEGORIA = "^[A-Za-záéíóúÁÉÍÓÚñÑ\\s]{3,50}$";
private static final String REGEX_CANTIDAD = "^\\d+$";
public static boolean validarCodigo(String v) { return v.matches(REGEX_CODIGO); }
public static boolean validarNombre(String v) { return v.matches(REGEX_NOMBRE); }
public static boolean validarDescripcion(String v){ return v.matches(REGEX_DESC); }
public static boolean validarPrecio(String v) { return v.matches(REGEX_PRECIO); }
public static boolean validarCategoria(String v) { return v.matches(REGEX_CATEGORIA); }
public static boolean validarCantidad(String v) { return v.matches(REGEX_CANTIDAD); }
}
Fuentes bibliográficas y documentación consultada para la elaboración de este blog, citadas en formato APA.