Esta publicación resume las principales preguntas formuladas sobre las expresiones regulares de Java. Como se preguntan con más frecuencia, es posible que también sean muy útiles.
1. ¿Cómo extraer números de una cadena?
Una pregunta común al usar expresiones regulares es extraer todos los números en una matriz de enteros.
En Java, d
significa un rango de dígitos (0-9). Usar las clases predefinidas siempre que sea posible hará que su código sea más fácil de leer y eliminará los errores introducidos por clases de caracteres mal formadas. Por favor refiérase a Clases de caracteres predefinidas para más detalles. Tenga en cuenta la primera barra invertida en
d
. Si está utilizando una construcción de escape dentro de un literal de cadena, debe preceder la barra invertida con otra barra invertida para que la cadena se compile. Es por eso que necesitamos usar d
.
List<Integer> numbers = new LinkedList<Integer>(); Pattern p = Pattern.compile("d+"); Matcher m = p.matcher(str); while (m.find()) { numbers.add(Integer.parseInt(m.group())); } |
2. ¿Cómo dividir Java String por líneas nuevas?
Hay al menos tres formas diferentes de ingresar un carácter de nueva línea, dependiendo del sistema operativo en el que esté trabajando.
r represents CR (Carriage Return), which is used in Unix n means LF (Line Feed), used in Mac OS rn means CR + LF, used in Windows
Por lo tanto, la forma más sencilla de dividir una cadena en nuevas líneas es
String lines[] = String.split("r?n"); |
Pero si no quieres líneas vacías, puedes usar, que también es mi forma favorita:
String.split("[rn]+") |
Una forma más robusta, que es realmente independiente del sistema, es la siguiente. Pero recuerde, seguirá obteniendo líneas vacías si dos caracteres de nueva línea se colocan uno al lado del otro.
String.split(System.getProperty("line.separator")); |
3. Importancia de Pattern.compile ()
Una expresión regular, especificada como una cadena, primero debe compilarse en una instancia de Patrón clase. Patrón.compilar() El método es la única forma de crear una instancia de objeto. Por tanto, una secuencia de invocación típica es
Pattern p = Pattern.compile("a*b"); Matcher matcher = p.matcher("aaaaab"); assert matcher.matches() == true; |
Esencialmente, Patrón.compilar() se utiliza para transformar una expresión regular en una máquina de estados finitos (ver Compiladores: principios, técnicas y herramientas (segunda edición)). Pero todos los estados involucrados en la realización de un partido residen en el emparejador. De esta manera, el Patrón pag se puede reutilizar. Y muchos comparadores pueden compartir el mismo patrón.
Matcher anotherMatcher = p.matcher("aab"); assert anotherMatcher.matches() == true; |
Patrón.partidos() El método se define como una conveniencia para cuando una expresión regular se usa solo una vez. Este método todavía usa compilar() para obtener la instancia de un Patrón implícitamente y coincide con una cadena. Por lo tanto,
boolean b = Pattern.matches("a*b", "aaaaab"); |
es equivalente al primer código anterior, aunque para coincidencias repetidas es menos eficiente ya que no permite reutilizar el patrón compilado.
4. ¿Cómo escapar del texto para una expresión regular?
En general, la expresión regular usa «» para escapar de las construcciones, pero es doloroso preceder la barra invertida con otra barra invertida para que la cadena de Java se compile. Hay otra forma para que los usuarios pasen literales de cadena al Patrón, como «$ 5». En lugar de escribir $5
o [$]5
, podemos escribir
Pattern.quote("$5"); |
5. ¿Por qué String.split () necesita un delimitador de tubería para escapar?
Cuerda.separar() divide una cadena alrededor de coincidencias de la expresión regular dada. La expresión Java admite caracteres especiales que afectan la forma en que se hace coincidir un patrón, que se llama metacarácter. |
es un metacarácter que se utiliza para hacer coincidir una sola expresión regular entre varias expresiones regulares posibles. Por ejemplo, A|B
significa ya sea A
o B
. Por favor refiérase a Alternancia con el símbolo de barra vertical o tubería para más detalles. Por lo tanto, para usar |
como literal, debe escapar agregando delante de ella, como
|
.
6. ¿Cómo podemos igualar unnorteBnorte con Java regex?
Este es el idioma de todas las cadenas no vacías que constan de un número de a
seguido de un número igual de b
es como ab
, aabb
, y aaabbb
. Se puede demostrar que este lenguaje es gramática libre de contexto S → aSb | ab, y por lo tanto un lenguaje no regular.
Sin embargo, las implementaciones de expresiones regulares de Java pueden reconocer más que solo lenguajes regulares. Es decir, no son «regulares» según la definición de la teoría formal del lenguaje. Utilizando mirar hacia el futuro y coincidencia de autorreferencia lo logrará. Aquí daré primero la expresión regular final y luego la explicaré un poco. Para una explicación completa, lo recomendaría leer ¿Cómo podemos hacer coincidir un ^ nb ^ n con Java regex?.
Pattern p = Pattern.compile("(?x)(?:a(?= a*(1?+b)))+1"); // true System.out.println(p.matcher("aaabbb").matches()); // false System.out.println(p.matcher("aaaabbb").matches()); // false System.out.println(p.matcher("aaabbbb").matches()); // false System.out.println(p.matcher("caaabbb").matches()); |
En lugar de explicar la sintaxis de esta compleja expresión regular, prefiero decir un poco cómo funciona.
- En la primera iteración, se detiene en la primera
a
luego mira hacia adelante (después de omitir algunosa
s usandoa*
) si hay unb
. Esto se logró utilizando(?:a(?= a*(1?+b)))
. Si coincide,1
, la coincidencia de autorreferencia, coincidirá con los elementos entre paréntesis muy internos, que es un solob
en la primera iteración. - En la segunda iteración, la expresión se detendrá en la segunda
a
, luego mira hacia adelante (de nuevo saltandoa
s) para ver si habráb
. Pero esta vez,1+b
es en realidad equivalente abb
, por lo tanto dosb
s tienen que coincidir. Si es así,1
será cambiado abb
después de la segunda iteración. - En el norteth iteración, la expresión se detiene en el norteth
a
y mira si hay norteb
s adelante.
De esta forma, la expresión puede contar el número de a
sy coincidir si el número de b
s seguido de a
es igual.
7. ¿Cómo reemplazar 2 o más espacios con un solo espacio en una cadena y eliminar solo los espacios iniciales?
Cuerda.reemplaza todo() reemplaza cada subcadena que coincide con la expresión regular dada con el reemplazo dado. «2 o más espacios» se pueden expresar mediante una expresión regular [ ]+
. Por lo tanto, el siguiente código funcionará. Tenga en cuenta que, en última instancia, la solución no eliminará todos los espacios en blanco iniciales y finales. Si desea que se eliminen, puede utilizar Cuerda.podar() En la tuberia.
String line = " aa bbbbb ccc d "; // " aa bbbbb ccc d " System.out.println(line.replaceAll("[s]+", " ")); |
8. ¿Cómo determinar si un número es primo con expresión regular?
public static void main(String[] args) { // false System.out.println(prime(1)); // true System.out.println(prime(2)); // true System.out.println(prime(3)); // true System.out.println(prime(5)); // false System.out.println(prime(8)); // true System.out.println(prime(13)); // false System.out.println(prime(14)); // false System.out.println(prime(15)); } public static boolean prime(int n) { return !new String(new char[n]).matches(".?|(..+?)1+"); } |
La función primero genera norte número de caracteres e intenta ver si esa cadena coincide .?|(..+?)1+
. Si es primo, la expresión devolverá falso y el !
invertirá el resultado.
La primera parte .?
solo intenta asegurarse de que 1 no sea un cebador. La parte mágica es la segunda parte donde se usa la referencia inversa. (..+?)1+
primer intento de coincidencias norte longitud de los caracteres, luego repítalo varias veces 1+
.
Por definición, un número primo es un número natural mayor que 1 que no tiene divisores positivos distintos de 1 y él mismo. Eso significa que si a = n * m luego a no es un primo. Nuevo Méjico se puede explicar con más detalle «repetir norte metro veces «, y eso es exactamente lo que hace la expresión regular: coincide norte longitud de caracteres usando (..+?)
, luego repítelo metro veces usando 1+
. Por lo tanto, si el patrón coincide, el número no es primo, de lo contrario lo es. Recuerda que !
invertirá el resultado.
9. ¿Cómo dividir una cadena separada por comas pero ignorando las comas entre comillas?
Ha llegado al punto en que las expresiones regulares se rompen. Es mejor y más ordenado escribir un divisor simple y maneja casos especiales como lo desee.
Alternativamente, puede imitar el funcionamiento de una máquina de estados finitos, utilizando una instrucción switch o if-else. Se adjunta un fragmento de código.
public static void main(String[] args) { String line = "aaa,bbb,"c,c",dd;dd,"e,e"; List<String> toks = splitComma(line); for (String t : toks) { System.out.println("> " + t); } } private static List<String> splitComma(String str) { int start = 0; List<String> toks = new ArrayList<String>(); boolean withinQuote = false; for (int end = 0; end < str.length(); end++) { char c = str.charAt(end); switch(c) { case ',': if (!withinQuote) { toks.add(str.substring(start, end)); start = end + 1; } break; case '"': withinQuote = !withinQuote; break; } } if (start < str.length()) { toks.add(str.substring(start)); } return toks; } |
10. Cómo usar backreferences en expresiones regulares de Java
Las referencias inversas son otra característica útil en la expresión regular de Java.