1. Introducción
En este tutorial, veremos cómo ordenar cadenas alfanuméricas por los números que contienen. Nos centraremos en eliminar todos los caracteres no numéricos de la cadena antes de ordenar varias cadenas por los caracteres numéricos que quedan.
Veremos casos extremos comunes, incluidos String s vacíos y números inválidos.
Finalmente, probaremos unitariamente nuestra solución para asegurarnos de que funciona como se espera.
2. Descripción del problema
Antes de comenzar, necesitamos describir lo que queremos que logre nuestro código. Para este problema en particular, haremos las siguientes suposiciones:
- Nuestras cadenas pueden contener solo números, solo letras o una combinación de los dos.
- Los números de nuestras cadenas pueden ser enteros o dobles.
- Cuando los números de una cadena están separados por letras, debemos eliminar la letra y condensar los dígitos. Por ejemplo, 2d3 se convierte en 23.
- Por simplicidad, cuando aparece un número no válido o faltante, debemos tratarlo como 0.
Con esto establecido, vamos a atascarnos en nuestra solución.
3. Una solución Regex
Dado que nuestro primer paso es buscar patrones numéricos dentro de nuestra Cadena de entrada , podemos utilizar expresiones regulares, comúnmente conocidas como expresiones regulares.
Lo primero que necesitamos es nuestra expresión regular. Queremos conservar todos los números enteros y los puntos decimales de la cadena de entrada . Podemos lograr nuestro objetivo con lo siguiente:
String DIGIT_AND_DECIMAL_REGEX = "[^\\d.]" String digitsOnly = input.replaceAll(DIGIT_AND_DECIMAL_REGEX, "");
Expliquemos brevemente lo que está sucediendo:
- '[^]' : Denota un conjunto negado, por lo que apunta a cualquier carácter no especificado por la expresión regular adjunta
- '\ d' - coincide con cualquier carácter de dígito (0 - 9)
- '.' - coincidir con cualquier "." personaje
Luego usamos el método String.replaceAll para eliminar cualquier carácter no especificado por nuestra expresión regular. Al hacer esto, podemos asegurarnos de que se puedan lograr los primeros tres puntos de nuestro objetivo.
A continuación, necesitamos agregar algunas condiciones para asegurarnos de que las cadenas vacías y no válidas devuelvan 0, mientras que las cadenas válidas devuelven un doble válido :
if("".equals(digitsOnly)) return 0; try { return Double.parseDouble(digitsOnly); } catch (NumberFormatException nfe) { return 0; }
Eso completa nuestra lógica. Todo lo que queda por hacer es conectarlo a un comparador para que podamos ordenar convenientemente Listas de cadenas de entrada .
Creemos un método eficiente para devolver nuestro comparador desde cualquier lugar que queramos:
public static Comparator createNaturalOrderRegexComparator() { return Comparator.comparingDouble(NaturalOrderComparators::parseStringToNumber); }
4. Prueba, prueba, prueba
¿De qué sirve el código sin pruebas para verificar su funcionalidad? Configuremos una prueba unitaria rápida para asegurarnos de que todo funcione como lo planeamos:
List testStrings = Arrays.asList("a1", "d2.2", "b3", "d2.3.3d", "c4", "d2.f4",); // 1, 2.2, 3, 0, 4, 2.4 testStrings.sort(NaturalOrderComparators.createNaturalOrderRegexComparator()); List expected = Arrays.asList("d2.3.3d", "a1", "d2.2", "d2.f4", "b3", "c4"); assertEquals(expected, testStrings);
En esta prueba unitaria, hemos empaquetado todos los escenarios que planeamos. Números no válidos, enteros, decimales y números separados por letras, todos incluidos en nuestra variable testStrings .
5. Conclusión
En este breve artículo, hemos demostrado cómo ordenar cadenas alfanuméricas en función de los números que contienen, haciendo uso de expresiones regulares para hacer el trabajo duro por nosotros.
Hemos manejado excepciones estándar que pueden ocurrir al analizar cadenas de entrada y hemos probado los diferentes escenarios con pruebas unitarias.
Como siempre, el código se puede encontrar en GitHub.