Java: compruebe si la cadena contiene una subcadena

Verificar si una cadena contiene una subcadena es una tarea común. En este artículo, exploraremos el enfoque central de Java y el enfoque de Apache Commons para resolver este problema.

Introducción

Verificar subcadenas dentro de una Cadena es una tarea bastante común en la programación. Por ejemplo, a veces deseamos romper una Cadena si contiene un delimitador en un punto. Otras veces, deseamos alterar el flujo si una Cadena contiene (o carece) de una determinada subcadena, que podría ser un comando.

Hay un par de formas de hacer esto en Java, y la mayoría de ellas son lo que esperarías ver también en otros lenguajes de programación. Sin embargo, un enfoque que es exclusivo de Java es el uso de una clase Pattern, que trataremos más adelante en este artículo.

Alternativamente, puede usar Apache Commons y la clase auxiliar StringUtils, que ofrece muchos métodos derivados de los métodos principales para este propósito.

Core Java

Cadena.contiene()

La primera y principal forma de comprobar la presencia de una subcadena es el método .contains(). Lo proporciona la propia clase String y es muy eficiente.

El método acepta una CharSequence y devuelve true si la secuencia está presente en la cadena en la que llamamos al método:

1
2
3
4
String string = "Java";
String substring = "va";

System.out.println(string.contains(substring));

Ejecutar esto produciría:

1
true

Nota: El método .contains() distingue entre mayúsculas y minúsculas. Si intentamos buscar "Va" en nuestra cadena, el resultado sería falso.

A menudo, para evitar este problema, dado que no estamos buscando la distinción entre mayúsculas y minúsculas, haría coincidir el caso de ambas cadenas antes de verificar:

1
2
3
System.out.println(string.toLowerCase().contains(substring.toLowerCase()));
// OR
System.out.println(string.toUpperCase().contains(substring.toUpperCase()));

String.indexOf()

El método .indexOf() es un poco más crudo que el método .contains(), pero sin embargo es el mecanismo subyacente que permite que el método .contains() funcione.

Devuelve el índice de la primera aparición de una subcadena dentro de una Cadena y ofrece algunos constructores para elegir:

1
2
3
4
indexOf(int ch)
indexOf(int ch, int fromIndex)
indexOf(String str)
indexOf(String str, int fromIndex)

Podemos buscar un solo carácter con o sin compensación o buscar una cadena con o sin compensación.

El método devolverá el índice de la primera aparición si está presente, y -1 si no:

1
2
3
4
5
6
7
String string = "Lorem ipsum dolor sit amet.";

// You can also use unicode for characters
System.out.println(string.indexOf('i'));
System.out.println(string.indexOf('i', 8));
System.out.println(string.indexOf("dolor"));
System.out.println(string.indexOf("Lorem", 10));

Ejecutar este código producirá:

1
2
3
4
6
19
12
-1
  • La primera ocurrencia de i está en la palabra ipsum, 6 lugares desde el inicio de la secuencia de caracteres.
  • La primera aparición de i con un desplazamiento de 8 (es decir, la búsqueda comienza en s de ipsum) está en la palabra sit, 19 lugares desde el principio.
  • La primera aparición de la cadena dolor está a 12 lugares del principio.
  • Y finalmente, no hay ninguna aparición de ‘Lorem’ con un desplazamiento de ‘10’.

En última instancia, el método .contains() llama al método .indexOf() para que funcione. Eso hace que .indexOf() sea inherentemente incluso más eficiente que su contraparte (aunque en una cantidad muy pequeña), aunque tiene un caso de uso ligeramente diferente.

Cadena.últimoÍndiceDe()

A diferencia del método .indexOf(), que devuelve la primera aparición, el método .lastIndexOf() devuelve el índice de la última aparición de un carácter o cadena, con o sin desplazamiento:

1
2
3
4
5
6
7
String string = "Lorem ipsum dolor sit amet.";

// You can also use unicode for characters
System.out.println(string.lastIndexOf('i'));
System.out.println(string.lastIndexOf('i', 8));
System.out.println(string.lastIndexOf("dolor"));
System.out.println(string.lastIndexOf("Lorem", 10));

Ejecutar este código producirá:

1
2
3
4
19
6
12
0

Algunos pueden estar un poco sorprendidos por los resultados y decir:

lastIndexOf('i', 8) debería haber devuelto 19 ya que esa es la última aparición del carácter después del octavo carácter en la Cadena

Lo que vale la pena señalar es que cuando se ejecuta el método .lastIndexOf(), la secuencia de caracteres se invierte. El conteo comienza en el carácter final y va hacia el primero.

Dicho esto, sí. El resultado esperado es 6, ya que es la última aparición del carácter después de omitir 8 elementos desde el final de la secuencia.

Patrón con Regex y Matcher

La clase Pattern es esencialmente una representación compilada de una expresión regular. Se usa junto con la clase Matcher para hacer coincidir secuencias de caracteres.

Esta clase funciona compilando primero un patrón. Luego asignamos otro patrón a una instancia Matcher, que usa el método .find() para comparar los patrones asignados y compilados.

Si coinciden, el método .find() da como resultado true. Si los patrones no coinciden, el método da como resultado falso.

1
2
3
4
Pattern pattern = Pattern.compile(".*" + "some" + ".*");

Matcher matcher = pattern.matcher("Here is some pattern!");
System.out.println(matcher.find());

Esto produciría:

1
true

Apache Commons

Debido a su utilidad y prevalencia en Java, muchos proyectos tienen Apache Commons incluido en el classpath. Es una gran biblioteca con muchas características útiles que se usan a menudo en producción, y la verificación de subcadenas no es una excepción.

Apache Commons ofrece la clase StringUtils con muchos métodos auxiliares para la manipulación de cadenas, verificación de valores nulos, etc. Para esta tarea, podemos utilizar cualquiera de los .contains(), .indexOf(), .lastIndexOf( ) o .containsIgnoreCase().

Si no, incluirlo es tan fácil como agregar una dependencia a su archivo pom.xml si está usando Maven:

1
2
3
4
5
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>{version}</version>
</dependency>

O agregándolo a través de Gradle:

1
compile group: 'org.apache.commons', name: 'commons-lang3', version: '{version}'

StringUtils.contains()

El método .contains() es bastante sencillo y muy similar al enfoque central de Java.

La única diferencia es que no llamamos al método en la cadena que estamos comprobando (ya que no hereda este método), sino que pasamos la cadena que estamos buscando junto con la cadena que estamos buscando. estoy buscando:

1
2
3
String string = "Checking for substrings within a String is a fairly common task in programming.";

System.out.println(StringUtils.contains(string, "common task"));

Ejecutar este código producirá:

1
true

Nota: Este método distingue entre mayúsculas y minúsculas.

StringUtils.indexOf()

Naturalmente, el método .indexOf() también funciona de manera muy similar al enfoque central de Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
String string = "Checking for substrings within a String is a fairly common task in programming.";

// Search for first occurrence of 'f'
System.out.println(StringUtils.indexOf(string, 'f'));

// Search for first occurrence of 'f', skipping the first 12 elements
System.out.println(StringUtils.indexOf(string, 'f', 12));

// Search for the first occurrence of the "String" string
System.out.println(StringUtils.indexOf(string, "String"));

Ejecutar este código producirá:

1
2
3
9
45
32

StringUtils.indexOfAny()

El método .indexOfAny() acepta un vararg de caracteres, en lugar de uno solo, lo que nos permite buscar la primera aparición de cualquiera de los caracteres pasados:

1
2
3
4
5
6
7
String string = "Checking for substrings within a String is a fairly common task in programming.";

// Search for first occurrence of 'f' or 'n', whichever comes first
System.out.println(StringUtils.indexOfAny(string, ['f', 'n']));

// Search for the first occurrence of "String" or "for", whichever comes first
System.out.println(StringUtils.indexOfAny(string, "String", "for"));

Ejecutar este código producirá:

1
2
6
9

StringUtils.indexOfAnyBut()

El método .indexOfAnyBut() busca la primera aparición de cualquier carácter que no esté en el conjunto provisto:

1
2
3
4
5
6
7
String string = "Checking for substrings within a String is a fairly common task in programming.";

// Search for first character outside of the provided set 'C' and 'h'
System.out.println(StringUtils.indexOfAny(string, ['C', 'h']));

// Search for first character outside of the provided set 'C' and 'h'
System.out.println(StringUtils.indexOfAny(string, ["Checking", "for"]));

Ejecutar este código producirá:

1
2
2
14

StringUtils.indexOfDifference()

El método .indexOfDifference() compara dos matrices de caracteres y devuelve el índice del primer carácter diferente:

1
2
3
4
String s1 = "Hello World!"
String s2 = "Hello world!"

System.out.println(StringUtils.indexOfDifference(s1, s2));

Ejecutar este código producirá:

1
6

StringUtils.indexOfIgnoreCase()

El método .indexOfIgnoreCase() devolverá el índice de la primera aparición de un carácter en una secuencia de caracteres, ignorando su caso:

1
2
3
4
String string = "Checking for substrings within a String is a fairly common task in programming."

System.out.println(StringUtils.indexOf(string, 'c'));
System.out.println(StringUtils.indexOfIgnoreCase(string, 'c'));

Ejecutar este código producirá:

1
2
3
0

StringUtils.lastIndexOf()

Y, por último, el método .lastIndexOf() funciona prácticamente igual que el método central regular de Java:

1
2
3
4
5
6
7
String string = "Lorem ipsum dolor sit amet.";

// You can also use unicode for characters
System.out.println(StringUtils.lastIndexOf(string, 'i'));
System.out.println(StringUtils.lastIndexOf(string, 'i', 8));
System.out.println(StringUtils.lastIndexOf(string, "dolor"));
System.out.println(StringUtils.lastIndexOf(string, "Lorem", 10));

Ejecutar este código producirá:

1
2
3
4
19
6
12
0

StringUtils.containsIgnoreCase()

El método .containsIgnoreCase() verifica si String contiene una subcadena, ignorando el caso:

1
2
3
String string = "Checking for substrings within a String is a fairly common task in programming.";

System.out.println(StringUtils.containsIgnoreCase(string, "cOmMOn tAsK"));

Ejecutar este código producirá:

1
true

StringUtils.containsOnly()

El método .containsOnly() verifica si una secuencia de caracteres contiene solo los valores especificados.

Esto puede ser un poco engañoso, por lo que otra forma de decirlo es: comprueba si la secuencia de caracteres se compone solo de los caracteres especificados. Acepta una cadena o una secuencia de caracteres:

1
2
3
String string = "Hello World!"
System.out.println(StringUtils.containsOnly(string, 'HleWord!'));
System.out.println(StringUtils.containsOnly(string, "wrld"));

Ejecutar esto producirá:

1
2
true
false

La cadena "Hello World!" de hecho está construida sólo con los caracteres de la secuencia 'HleWord!'.

Nota: No es necesario usar todos los caracteres de la secuencia en la cadena para que el método devuelva verdadero. Lo que importa es que string no contiene un carácter que no esté en la secuencia de caracteres.

StringUtils.containsNone()

El método .containsNone() comprueba si la cadena contiene cualquier de los caracteres "prohibidos" de un conjunto. Si lo hace, se devuelve falso y viceversa:

1
2
3
String string = "Hello World!"
System.out.println(StringUtils.containsNone(string, 'xmt'));
System.out.println(StringUtils.containsNone(string, "wrld"));

Ejecutar este código produce:

1
2
true
false

StringUtils.containsAny()

Y finalmente, el método .containsAny() devuelve true si una secuencia de caracteres contiene alguno de los parámetros pasados ​​en forma de secuencia de caracteres o String:

1
2
3
String string = "Hello World!"
System.out.println(StringUtils.containsAny(string, ['h', 'm']));
System.out.println(StringUtils.containsAny(string, "hell"));

Este código produciría:

1
2
true
true

Conclusión

En conclusión, hay muchas formas de verificar una subcadena en una Cadena. El enfoque central de Java será suficiente en la mayoría de los casos, aunque si necesita verificar con más de una sola condición, Apache Commons es un verdadero ahorro de tiempo.

En muchos casos, definir su propia lógica para un método como .indexOfAnyBut() sería una molestia y simplemente redundante. Dado que la mayoría de los proyectos en la actualidad ya tienen Apache Commons en el classpath, lo más probable es que simplemente pueda usar los métodos proporcionados por la clase StringUtils. tils`.

Licensed under CC BY-NC-SA 4.0