137 votes

String.replaceTous les backslashes simples par des backslashes doubles

J'essaie de convertir le String \something\ dans le String \\something\\ en utilisant replaceAll mais je continue à obtenir toutes sortes d'erreurs. Je pensais que c'était la solution :

theString.replaceAll("\\", "\\\\");

Mais cela donne l'exception ci-dessous :

java.util.regex.PatternSyntaxException: Unexpected internal error near index 1

232voto

BalusC Points 498232

Le site String#replaceAll() interprète l'argument comme un expression régulière . Le site \ est un caractère d'échappement dans les deux String y regex . Vous devez l'écrire deux fois pour les regex :

string.replaceAll("\\\\", "\\\\\\\\");

Mais vous n'avez pas nécessairement besoin de regex pour cela, simplement parce que vous voulez un remplacement exact caractère par caractère et que vous n'avez pas besoin de motifs ici. Donc String#replace() devrait suffire :

string.replace("\\", "\\\\");

Mise à jour : selon les commentaires, vous semblez vouloir utiliser la chaîne dans un contexte JavaScript. Vous feriez peut-être mieux d'utiliser StringEscapeUtils#escapeEcmaScript() pour couvrir plus de personnages.

0 votes

En fait, il est utilisé dans un AST JavaScript qui doit être reconverti en source. Votre solution fonctionne. Merci !

3 votes

Si vous voulez utiliser String#replaceAll() de toute façon, vous pouvez citer la chaîne de remplacement avec Matcher#quoteReplacement() : theString.replaceAll("\\", Matcher.quoteReplacement("\\\\"));

1 votes

Matcher.quoteReplacement( ... ) est une bonne solution ! Veuillez consulter la réponse de Pshemo !

21voto

Pshemo Points 34648

TLDR : utiliser theString = theString.replace("\\", "\\\\"); à la place.


Problema

replaceAll(target, replacement) utilise la syntaxe des expressions régulières (regex) pour target et partiellement pour replacement .

Le problème est que \ est un caractère spécial dans les regex (il peut être utilisé comme suit \d pour représenter un chiffre) et dans les chaînes de caractères (il peut être utilisé comme suit "\n" pour représenter le séparateur de ligne ou \" pour échapper au symbole du guillemet double qui représente normalement la fin de la chaîne de caractères).

Dans ces deux cas, pour créer \ symbole que nous pouvons s'échapper (en le rendant littéral au lieu d'un caractère spécial) en plaçant un \ avant elle (comme nous échappons " dans les littéraux de chaînes de caractères via \" ).

Ainsi, pour target regex représentant \ Le symbole devra tenir \\ et la chaîne littérale représentant ce texte devra ressembler à ceci "\\\\" .

Nous nous sommes donc échappés \ deux fois :

  • une fois en regex \\
  • une fois dans la chaîne littérale "\\\\" (chaque \ est représenté par "\\" ).

En cas de replacement \ est également spécial là-bas. Il nous permet d'échapper à d'autres caractères spéciaux $ qui via $x la notation, nous permet d'utiliser la partie des données correspondant à la regex et détenue par le groupe de capture indexé comme x comme "012".replaceAll("(\\d)", "$1$1") correspondra à chaque chiffre, le placera dans le groupe de capture 1 et $1$1 le remplacera par ses deux copies (il le dupliquera), ce qui donnera comme résultat "001122" .

Donc, encore une fois, pour laisser replacement représenter \ littéral, nous devons lui échapper avec des \ ce qui signifie que :

  • le remplacement doit contenir deux caractères backslash \\
  • et le littéral String qui représente \\ ressemble à "\\\\"

MAIS puisque nous voulons replacement pour tenir deux backslashes dont nous aurons besoin "\\\\\\\\" (chaque \ représenté par un "\\\\" ).

Donc version avec replaceAll peut ressembler à

replaceAll("\\\\", "\\\\\\\\");

Un moyen plus facile

Pour nous faciliter la vie, Java fournit des outils permettant d'échapper automatiquement du texte dans des fichiers de type target y replacement pièces. Nous pouvons donc maintenant nous concentrer uniquement sur les chaînes de caractères, et oublier la syntaxe des regex :

replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))

qui, dans notre cas, peut ressembler à

replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))

Encore mieux

Si nous n'avons pas vraiment besoin du support de la syntaxe regex, n'impliquons pas replaceAll du tout. Utilisons plutôt replace . Les deux méthodes remplaceront todo target mais replace n'implique pas de syntaxe regex. Vous pouvez donc simplement écrire

theString = theString.replace("\\", "\\\\");

14voto

Fabian Steeg Points 24261

Pour éviter ce genre de problème, vous pouvez utiliser replace (qui prend une simple chaîne de caractères) au lieu de replaceAll (qui prend une expression régulière). Vous devrez toujours échapper les barres obliques inversées, mais pas de la manière sauvage requise avec les expressions régulières.

8voto

sfussenegger Points 16204

Vous devrez échapper la barre oblique inverse (échappée) dans le premier argument car il s'agit d'une expression régulière. Remplacement (2e argument - voir Matcher#replaceAll(Chaîne) ) a également sa propre signification des antislashes, vous devrez donc les remplacer par :

theString.replaceAll("\\\\", "\\\\\\\\");

3voto

Jonathan Feinberg Points 24791

Oui... au moment où le compilateur regex voit le motif que vous lui avez donné, il ne voit qu'une seule barre oblique inversée (puisque le lexer de Java a transformé la double barre oblique inversée en une seule). Vous devez remplacer "\\\\" con "\\\\" croyez-le ou non ! Java a vraiment besoin d'une bonne syntaxe de chaîne brute.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X