Question Regex - Un ou plusieurs espaces en dehors d'une citation, bloc de texte fermé
Question
Je souhaite remplacer toute occurrence de plusieurs espaces par un seul, mais aucune action en texte entre guillemets.
Existe-t-il un moyen de faire cela avec une expression rationnelle Java? Si oui, pouvez-vous essayer ou me donner un indice?
La solution
Voici une autre approche, qui consiste à regarder avant pour déterminer que tous les guillemets après la position actuelle sont placés par paires.
text = text.replaceAll(" ++(?=(?:[^\"]*+\"[^\"]*+\")*+[^\"]*+$)", " ");
Si nécessaire, le lookahead peut être adapté pour gérer les guillemets échappés à l'intérieur des sections citées.
Autres conseils
Lorsque vous essayez de faire correspondre quelque chose qui peut être contenu dans quelque chose d'autre, il peut être utile de construire une expression régulière qui correspond aux deux, comme ceci:
("[^"\\]*(?:\\.[^"\\]*)*")|( +)
Ceci correspondra à une chaîne entre guillemets ou à deux espaces ou plus. Comme les deux expressions sont combinées, cela correspond à une chaîne entre guillemets OU à deux espaces ou plus, mais pas aux guillemets. En utilisant cette expression, vous devrez examiner chaque correspondance pour déterminer s’il s’agit d’une chaîne entre guillemets ou de deux espaces ou plus et agir en conséquence:
Pattern spaceOrStringRegex = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|( +)" );
StringBuffer replacementBuffer = new StringBuffer();
Matcher spaceOrStringMatcher = spaceOrStringRegex.matcher( text );
while ( spaceOrStringMatcher.find() )
{
// if the space group is the match
if ( spaceOrStringMatcher.group( 2 ) != null )
{
// replace with a single space
spaceOrStringMatcher.appendReplacement( replacementBuffer, " " );
}
}
spaceOrStringMatcher.appendTail( replacementBuffer );
texte entre guillemets: les guillemets sont-ils sur la même ligne ou sur plusieurs lignes?
Personnellement, je n'utilise pas Java, mais cette RegExp pourrait faire l'affaire:
([^\" ])*(\\\".*?\\\")*
Essayer l'expression avec RegExBuddy, il génère ce code, il me semble bien:
try {
Pattern regex = Pattern.compile("([^\" ])*(\\\".*?\\\")*", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
for (int i = 1; i <= regexMatcher.groupCount(); i++) {
// matched text: regexMatcher.group(i)
// match start: regexMatcher.start(i)
// match end: regexMatcher.end(i)
// I suppose here you must use something like
// sstr += regexMatcher.group(i) + " "
}
}
} catch (PatternSyntaxException ex) {
// Syntax error in the regular expression
}
Au moins, cela semble fonctionner correctement en Python:
import re
text = """
este es un texto de prueba "para ver como se comporta " la funcion sobre esto
"para ver como se comporta " la funcion sobre esto "o sobre otro" lo q sea
"""
ret = ""
print text
reobj = re.compile(r'([^\" ])*(\".*?\")*', re.IGNORECASE)
for match in reobj.finditer(text):
if match.group() <> "":
ret = ret + match.group() + "|"
print ret
Après avoir analysé le contenu cité, exécutez ce travail sur le reste, en bloc ou pièce par pièce, si nécessaire:
String text = "ABC DEF GHI JKL";
text = text.replaceAll("( )+", " ");
// text: "ABC DEF GHI JKL"
Jeff, vous êtes sur la bonne voie, mais votre code contient quelques erreurs, à savoir: (1) vous avez oublié d'échapper aux guillemets dans les classes de caractères annulées; (2) Les parenthèses du premier groupe de capture auraient dû appartenir à la variété sans capture; (3) Si le deuxième ensemble d'entités capturantes ne participe pas à une correspondance, group (2)
renvoie la valeur null et vous ne testez pas pour cela; et (4) Si vous testez deux ou plus espaces dans la regex au lieu de un ou plusieurs , vous n'avez pas besoin de vérifier la longueur de la correspondance ultérieurement. Voici le code révisé:
import java.util.regex.*;
public class Test
{
public static void main(String[] args) throws Exception
{
String text = "blah blah \"boo boo boo\" blah blah";
Pattern p = Pattern.compile( "(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\")|( +)" );
StringBuffer sb = new StringBuffer();
Matcher m = p.matcher( text );
while ( m.find() )
{
if ( m.group( 2 ) != null )
{
m.appendReplacement( sb, " " );
}
}
m.appendTail( sb );
System.out.println( sb.toString() );
}
}