Dans le travail d'un programmeur, certaines tâches ou leurs composants peuvent souvent être répétés. C'est pourquoi je voudrais aujourd'hui aborder un sujet souvent rencontré dans le travail quotidien de tout développeur Java. Supposons que vous receviez une certaine chaîne d'une certaine méthode. Et tout semble bien, mais il y a une petite chose qui ne vous convient pas. Par exemple, le séparateur ne convient pas et il vous en faut un autre (ou pas du tout). Que peut-on faire dans une telle situation ? Naturellement, utilisez les méthodes
replace
de la classe String
.
Remplacement de la chaîne Java
L'objet typeString
a quatre variantes de la méthode de remplacementreplace
:
replace(char, char);
replace(CharSequence, CharSequence);
replaceFirst(String, String);
replaceAll(String, String).
replace(char, char)
String replace(char oldChar, char newChar)
- remplace toutes les occurrences du caractère du premier argument oldChar
par le second - newChar
. Dans cet exemple, nous remplacerons la virgule par un point-virgule :
String value = "In JavaRush, Diego the best, Diego is Java God".replace(',', ';');
System.out.println(value);
Sortie de la console :
In JavaRush; Diego the best; Diego is Java God
2.replace(CharSequence, CharSequence)
Remplace chaque sous-chaîne d'une chaîne qui correspond à une séquence de caractères spécifiée par une séquence de caractères de remplacement.
String value = "In JavaRush, Diego the best, Diego is Java God".replace("Java", "Rush");
System.out.println(value);
Conclusion:
In RushRush, Diego the best, Diego is Rush God
3.replaceFirst(String, String)
String replaceFirst(String regex, String replacement)
- Remplace la première sous-chaîne qui correspond à l'expression régulière spécifiée par une chaîne de remplacement. Lorsque vous utilisez une expression régulière non valide, vous pouvez intercepter une PatternSyntaxException (ce qui n'est pas une bonne chose). Dans cet exemple, remplaçons le nom du robot champion :
String value = "In JavaRush, Diego the best, Diego is Java God".replaceFirst("Diego", "Amigo");
System.out.println(value);
Sortie de la console :
In JavaRush, Amigo the best, Diego is Java God
Comme nous pouvons le constater, seule la première entrée de « Diego » a changé, mais les suivantes sont restées laissées de côté, c'est-à-dire intactes. 4. replaceAll()
en Java String replaceAll(String regex, String replacement)
- cette méthode remplace toutes les occurrences d'une sous-chaîne dans une chaîne regex
par replacement
. Une expression régulière peut être utilisée comme premier argument regex
. A titre d'exemple, essayons d'effectuer le remplacement précédent par des noms, mais avec une nouvelle méthode :
String value = "In JavaRush, Diego the best, Diego is Java God".replaceAll("Diego", "Amigo");
System.out.println(value);
Sortie de la console :
In JavaRush, Amigo the best, Amigo is Java God
Comme nous pouvons le constater, tous les symboles ont été complètement remplacés par ceux nécessaires. Je pense qu'Amigo sera content =)
Expressions régulières
Il a été dit plus haut qu'il était possible de remplacer à l'aide d'une expression régulière. Tout d’abord, clarifions par nous-mêmes ce qu’est une expression régulière ? Les expressions régulières sont un langage formel permettant de rechercher et de manipuler des sous-chaînes dans un texte, basé sur l'utilisation de métacaractères (caractères génériques). En termes simples, il s'agit d'un modèle de caractères et de métacaractères qui définit une règle de recherche. Par exemple :\D
- un modèle décrivant tout caractère non numérique ; \d
— définit tout caractère numérique, qui peut également être décrit comme [0-9]
; [a-zA-Z]
— un modèle décrivant les caractères latins de a à z, insensible à la casse ; Considérons l'application dans une méthode replaceAll
de classeString
:
String value = "In JavaRush, Diego the best, Diego is Java God".replaceAll("\\s[a-zA-Z]{5}\\s", " Amigo ");
System.out.println(value);
Sortie de la console :
In JavaRush, Amigo the best, Amigo is Java God
\\s[a-zA-Z]{5}\\s
— décrit un mot de 5 caractères latins entourés d'espaces. En conséquence, ce modèle est remplacé par la chaîne que nous avons transmise.
Remplacement de l'expression régulière Java
Fondamentalement, pour utiliser des expressions régulières en Java, les capacités dujava.util.regex
. Les classes clés sont :
Pattern
- une classe qui fournit une version compilée d'une expression régulière.Matcher
— cette classe interprète le modèle et détermine les correspondances dans la chaîne qu'elle reçoit.
Matcher
et Pattern
:
Pattern pattern = Pattern.compile("\\s[a-zA-Z]{5}\\s");
Matcher matcher = pattern.matcher("In JavaRush, Diego the best, Diego is Java God");
String value = matcher.replaceAll(" Amigo ");
System.out.println(value);
Et notre conclusion sera la même :
In JavaRush, Amigo the best, Amigo is Java God
Vous pouvez en savoir plus sur les expressions régulières dans cet article .
Alternative à replaceAll
Il ne fait aucun doute que les méthodesreplace
sont String
très impressionnantes, mais on ne peut ignorer le fait qu’il String
s’agit immutable
d’un objet, c’est-à-dire qu’il ne peut pas être modifié après sa création. Par conséquent, lorsque nous remplaçons certaines parties d'une chaîne à l'aide de méthodes replace
, nous ne modifions pas l'objet String
, mais en créons un nouveau à chaque fois, avec le contenu nécessaire. Mais il faut beaucoup de temps pour créer un nouvel objet à chaque fois, n'est-ce pas ? Surtout quand il ne s'agit pas de quelques objets, mais de quelques centaines, voire milliers. Bon gré mal gré, vous commencez à réfléchir à des alternatives. Et quelles alternatives avons-nous ? Hmm... Quand il s'agit de String
sa propriété immutable
, vous pensez immédiatement à des alternatives, mais pas immutable
, à savoir StringBuilder/StringBuffer . Comme nous nous en souvenons, ces classes ne diffèrent pas réellement, sauf qu'elles StringBuffer
sont optimisées pour une utilisation dans un environnement multithread, StringBuilder
elles fonctionnent donc un peu plus rapidement en utilisation monothread. Sur cette base, nous utiliserons aujourd'hui StringBuilder.
Cette classe a de nombreuses méthodes intéressantes, mais c'est précisément ce qui nous intéresse maintenant replace
. StringBuilder replace(int start, int end, String str)
— cette méthode remplace les caractères d'une sous-chaîne de cette séquence par des caractères de la chaîne spécifiée. La sous-chaîne commence au début spécifié et continue jusqu'au caractère à la fin de l'index, -1
ou jusqu'à la fin de la séquence si aucun caractère de ce type n'existe. Regardons un exemple :
StringBuilder strBuilder = new StringBuilder("Java Rush");
strBuilder.replace(5, 9, "God");
System.out.println(strBuilder);
Conclusion:
Java God
Comme vous pouvez le voir, nous indiquons l'intervalle dans lequel nous voulons écrire la chaîne et écrivons une sous-chaîne au-dessus de ce qui se trouve dans l'intervalle. Ainsi, en utilisant l'aide, StringBuilder
nous allons recréer un analogue de la méthode replaceall java
. À quoi cela ressemblera-t-il :
public static String customReplaceAll(String str, String oldStr, String newStr) {
if ("".equals(str) || "".equals(oldStr) || oldStr.equals(newStr)) {
return str;
}
if (newStr == null) {
newStr = "";
}
final int strLength = str.length();
final int oldStrLength = oldStr.length();
StringBuilder builder = new StringBuilder(str);
for (int i = 0; i < strLength; i++) {
int index = builder.indexOf(oldStr, i);
if (index == -1) {
if (i == 0) {
return str;
}
return builder.toString();
}
builder = builder.replace(index, index + oldStrLength, newStr);
}
return builder.toString();
}
Cela fait peur à première vue, mais avec un peu de compréhension on comprend que tout n'est pas si compliqué et assez logique. Nous avons trois arguments :
str
— une ligne dans laquelle on souhaite remplacer certaines sous-chaînes ;oldStr
— représentation des sous-chaînes que nous remplacerons ;newStr
- par quoi nous allons le remplacer.
if
Nous avons besoin du premier pour vérifier les données entrantes, et si la chaîne str
est oldStr
vide ou si la nouvelle sous-chaîne newStr
est égale à l'ancienne oldStr
, alors l'exécution de la méthode n'aura aucun sens. Par conséquent, nous renvoyons la chaîne d'origine - str
. Ensuite, nous vérifions newStr
, null
et si tel est le cas, nous le convertissons dans un format de chaîne vide qui nous convient mieux - ""
. Ensuite nous avons la déclaration des variables dont nous avons besoin :
- longueur totale de la chaîne
str
; - longueur de la sous-chaîne
oldStr
; - objet
StringBuilder
à partir d’une chaîne partagée.
StringBuilder
- indexOf
- nous trouvons l'index de la première occurrence de la sous-chaîne qui nous intéresse. Malheureusement, je voudrais noter que cela indexOf
ne fonctionne pas avec les expressions régulières, donc notre méthode finale ne fonctionnera qu'avec les occurrences de chaînes (( Si cet index est égal à -1
, alors il n'y a plus d'occurrences de ces occurrences dans l'objet actuel StringBuilder
, nous quittons donc la méthode avec le résultat qui nous intéresse : il est contenu dans notre StringBuilder
, que nous convertissons en String
, en utilisant toString
. Si notre index est égal -1
à la première itération de la boucle, alors la sous-chaîne qui doit être remplacée n'était pas dans le général chaîne initialement. Par conséquent, dans une telle situation, nous renvoyons simplement la chaîne générale. Ensuite, nous avons et la méthode décrite ci-dessus est utilisée replace
pour StringBuilder
utiliser l'index trouvé de l'occurrence pour indiquer les coordonnées de la sous-chaîne à remplacer. Cette boucle s'exécutera autant de fois que de sous-chaînes à remplacer sont trouvées. Si la chaîne est constituée uniquement du caractère à remplacer, alors seulement dans ce cas nous avons La boucle s'exécutera complètement et nous obtiendrons le résultat StringBuilder
converti en chaîne. Nous devons vérifier l’exactitude de cette méthode, n’est-ce pas ? Écrivons un test qui vérifie le fonctionnement de la méthode dans diverses situations :
@Test
public void customReplaceAllTest() {
String str = "qwertyuiop__qwertyuiop__";
String firstCase = Solution.customReplaceAll(str, "q", "a");
String firstResult = "awertyuiop__awertyuiop__";
assertEquals(firstCase, firstResult);
String secondCase = Solution.customReplaceAll(str, "q", "ab");
String secondResult = "abwertyuiop__abwertyuiop__";
assertEquals(secondCase, secondResult);
String thirdCase = Solution.customReplaceAll(str, "rtyu", "*");
String thirdResult = "qwe*iop__qwe*iop__";
assertEquals(thirdCase, thirdResult);
String fourthCase = Solution.customReplaceAll(str, "q", "");
String fourthResult = "wertyuiop__wertyuiop__";
assertEquals(fourthCase, fourthResult);
String fifthCase = Solution.customReplaceAll(str, "uio", "");
String fifthResult = "qwertyp__qwertyp__";
assertEquals(fifthCase, fifthResult);
String sixthCase = Solution.customReplaceAll(str, "", "***");
assertEquals(sixthCase, str);
String seventhCase = Solution.customReplaceAll("", "q", "***");
assertEquals(seventhCase, "");
}
Peut être divisé en 7 tests distincts, chacun étant responsable de son propre scénario de test. Après l'avoir lancé, nous verrons qu'il est vert, c'est-à-dire réussi. Eh bien, cela semble être tout. Attendez, nous avons dit plus haut que cette méthode sera beaucoup plus rapide replaceAll
que String
. Voyons voir:
String str = "qwertyuiop__qwertyuiop__";
long firstStartTime = System.nanoTime();
for (long i = 0; i < 10000000L; i++) {
str.replaceAll("tyu", "#");
}
double firstPerformance = System.nanoTime() - firstStartTime;
long secondStartTime = System.nanoTime();
for (long i = 0; i < 10000000L; i++) {
customReplaceAll(str, "tyu", "#");
}
double secondPerformance = System.nanoTime() - secondStartTime;
System.out.println("Performance ratio - " + firstPerformance / secondPerformance);
Ensuite, ce code a été exécuté trois fois et nous avons obtenu les résultats suivants : Sortie de la console :
Performance ratio - 5.012148941181627
Performance ratio - 5.320637176017641
Performance ratio - 4.719192686500394
Comme nous pouvons le constater, en moyenne notre méthode est 5 fois plus productive que le replaceAll
cours classique ! String
Eh bien, enfin, effectuons le même contrôle, mais, pour ainsi dire, en vain. En d’autres termes, dans le cas où aucune correspondance n’est trouvée. Remplaçons la chaîne de recherche de "tyu"
par "--"
. Trois exécutions ont donné les résultats suivants : Sortie de la console :
Performance ratio - 8.789647093542246
Performance ratio - 9.177105482660881
Performance ratio - 8.520964375227406
En moyenne, les performances dans les cas où aucune correspondance n'a été trouvée ont été multipliées par 8,8 !
GO TO FULL VERSION