Question:
I'm trying to make a method that finds and replaces words using regular expressions. The point is that I must be able to find and replace the word regardless of whether it has capital letters or not. This is the code I have:
public String reemplazar(String cadena,JFrame frame){
StringBuffer reemplazar = new StringBuffer();
StringBuffer buscar = new StringBuffer();
StringBuffer respuesta = new StringBuffer();
DlgReemplazar dlgReemplazar = new DlgReemplazar(
frame, true, buscar, reemplazar, constantesGUI.REEMPLAZAR, respuesta
);
dlgReemplazar.setVisible(true);
Pattern pat = Pattern.compile(buscar.toString(), Pattern.CASE_INSENSITIVE);
Matcher mat = pat.matcher(cadena);
if (mat.find() == true) {
cadena = cadena.replaceAll(
String.valueOf(buscar), String.valueOf(reemplazar)
);
}else{
JOptionPane.showMessageDialog(null, "No se encontro el texto");
}
return cadena;
}
Answer:
The first point to correct is that special characters that may be in the variable must be escaped. For example, if the user enters [hola]
, I understand that it should search for that literal text, and not just one of those 4 characters.
To obtain a literal pattern from a string, Pattern.quote() is used.
String patronBuscado = Pattern.quote(buscar.toString());
- It would not need to be escaped if the Pattern.LITERAL modifier is used, although I personally prefer to do it without this modifier for clarity or to allow only part of the pattern to be escaped.
And the same goes for replacement, where you should use Matcher.quoteReplacement() .
String patronReemplazo = Matcher.quoteReplacement(reemplazar.toString());
Now yes, let's get to the main thing. As you may have seen, String.replaceAll() does not accept modifiers like Pattern.CASE_INSENSITIVE
, nor a Pattern
, only Strings.
There are 3 ways to replace regardless of case.
-
Passing the inline modifier as
(?i)
inside the regular expression:cadena = cadena.replaceAll( "(?i)" + patronBuscado, patronReemplazo);
-
Use Matcher.replaceAll() on a compiled regular expression:
Pattern pat = Pattern.compile(patronBuscado, Pattern.CASE_INSENSITIVE); Matcher mat = pat.matcher(cadena); cadena = mat.replaceAll(patronReemplazo);
-
Alternatively, the Matcher.appendReplacement() and Matcher.appendTail() methods can be used to replace with a StringBuffer and have greater control over each of the replacements. However, this is unnecessary if you simply want to replace all occurrences with the same value.
Finally, note that Pattern.CASE_INSENSITIVE
only works in the ASCII range. If you wanted to replace accents as well, you should add Pattern.UNICODE_CASE (or the inline modifier (?iu)
):
Pattern pat = Pattern.compile(patronBuscado, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Code:
String cadena = "Respuesta de SO en inglés";
StringBuffer buscar = new StringBuffer("EN INGLÉS");
String patronBuscado = Pattern.quote(buscar.toString());
StringBuffer reemplazar = new StringBuffer("en español");
String patronReemplazo = Matcher.quoteReplacement(reemplazar.toString());
Pattern pat = Pattern.compile(patronBuscado, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Matcher mat = pat.matcher(cadena);
if (mat.find()) {
cadena = mat.replaceAll(patronReemplazo);
System.out.println("Resultado: " + cadena);
} else {
System.out.println("No se encontro el texto");
}
Demo: