Comment échapper% dans String.Format?

446

Je stocke une requête SQL dans mon fichier strings.xml et je souhaite utiliser String.Formatpour créer la chaîne finale dans le code. L' SELECTinstruction utilise un like, quelque chose comme ceci:

SELECT Field1, Field2 FROM mytable WHERE Field1 LIKE '%something%'

Afin de formater ce que je remplace «quelque chose» par% 1 $ s, il devient:

SELECT Field1, Field2 FROM mytable WHERE Field1 LIKE \'%%1$s%\'

J'échappe aux guillemets simples avec la barre oblique inverse. Cependant, je ne parviens pas à échapper au signe%.

Comment puis-je inclure une instruction similaire dans mon fichier strings.xml?

Matthieu
la source
N'oubliez pas d'échapper correctement au% s.
Seva Alekseyev
Ils injecteraient dans leur propre base de données, pas de souci ici;)
Matthew
7
Eh bien, même s'il s'agit de votre propre base de données, il est possible d'écrire accidentellement des requêtes qui font de mauvaises choses. Ou écrivez simplement des requêtes qui ne se compilent pas. La préparation de requêtes est une bonne habitude à prendre.
Rauni Lillemets
Bien qu'il soit plus lent que String.format()vous n'envisagez d'utiliser à la MessageFormat()place.
ccpizza

Réponses:

928

Pour échapper %, vous devrez doubler jusqu'à: %%.

limc
la source
14

Pour compléter la solution précédente, utilisez:

str = str.replace("%", "%%");
Cavaleiro
la source
1
Cela remplacera les% déjà doublés. Veuillez lire l'autre réponse.
Toilal
1
@Toilal Pourquoi quelqu'un échapperait-il à quelque chose qui s'est déjà échappé? Et s'il le voulait, pourquoi ne pas le faire? Peut-être qu'il avait l'intention d'avoir deux signes%, donc la forme d'échappement correcte serait '%%%%'
David Balažic
2

Il s'agit d'un remplacement regex plus fort qui ne remplacera pas les %% déjà doublés en entrée.

str = str.replaceAll("(?:[^%]|\\A)%(?:[^%]|\\z)", "%%");
Toilal
la source
-3

Voici une option si vous devez échapper plusieurs% dans une chaîne avec certains déjà échappés.

(?:[^%]|^)(?:(%%)+|)(%)(?:[^%])

Pour filtrer le message avant de le transmettre à String.format, vous pouvez utiliser ce qui suit

Pattern p = Pattern.compile("(?:[^%]|^)(?:(%%)+|)(%)(?:[^%])");
Matcher m1 = p.matcher(log);

StringBuffer buf = new StringBuffer();
while (m1.find())
    m1.appendReplacement(buf, log.substring(m1.start(), m1.start(2)) + "%%" + log.substring(m1.end(2), m1.end()));

// Return the sanitised message
String escapedString = m1.appendTail(buf).toString();

Cela fonctionne avec n'importe quel nombre de caractères de formatage, il remplacera donc% par %%, %%% par %%%%, %%%%% par %%%%%% etc.

Il laissera seuls les caractères déjà échappés (par exemple %%, %%%% etc.)

Lee Winder
la source
8
"Je ne peux pas croire que ce ne soit pas un simple problème résolu" "Vous avez répondu 6 ans après qu'une solution simple ait été acceptée.
AjahnCharles