Regex correspondant aux espaces blancs - Java

106

Les états de l' API Java pour les expressions régulières qui \scorrespondent aux espaces. Ainsi, l'expression régulière \\s\\sdoit correspondre à deux espaces.

Pattern whitespace = Pattern.compile("\\s\\s");
matcher = whitespace.matcher(modLine);
while (matcher.find()) matcher.replaceAll(" ");

Le but de ceci est de remplacer toutes les instances de deux espaces blancs consécutifs par un seul espace. Cependant, cela ne fonctionne pas réellement.

Ai-je un grave malentendu sur les expressions régulières ou le terme «espace blanc»?


la source
1
String a une fonction replaceAll qui vous fera économiser quelques lignes de code. download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html
Zach L
1
Ce n'est pas votre malentendu, mais celui de Java. Essayez de diviser une chaîne comme "abc \xA0 def \x85 xyz"pour voir ce que je veux dire: il n'y a que trois champs.
tchrist
3
Avez-vous essayé "\\ s +". Avec cela, vous remplacez deux ou plusieurs espaces par un.
hrzafer
Je me demande depuis plus d'une heure pourquoi ma division ne se divise pas sur des espaces. Mille mercis!
Marcin

Réponses:

44

Ouais, vous devez saisir le résultat de matcher.replaceAll():

String result = matcher.replaceAll(" ");
System.out.println(result);
Raph Levien
la source
18
Gah. Je me sens le plus grand idiot du monde. Ni moi ni deux autres personnes ne semblaient remarquer cela. Je suppose que les petites erreurs les plus stupides nous dérangent parfois, hein?
Tellement vrai! Je suppose que cela arrive avec les meilleurs d'entre eux
saibharath
Que se passe-t-il si j'ai besoin d'obtenir si le texte avait des espaces blancs.?
Gilberto Ibarra
Selon ma réponse ci-dessous, utilisez \ p {Zs} au lieu de \ s si vous voulez faire correspondre les espaces unicode.
Robert
194

Vous ne pouvez pas utiliser \sen Java pour faire correspondre l'espace blanc sur son propre jeu de caractères natif, car Java ne prend pas en charge la propriété d'espace blanc Unicode - même si cela est strictement nécessaire pour respecter la RL1.2 de UTS # 18! Ce qu'il a n'est hélas pas conforme aux normes.

Unicode définit 26 points de code comme suit \p{White_Space}: 20 d'entre eux sont différentes sortes de \pZ GeneralCategory = Separator , et les 6 restants sont \p{Cc} GeneralCategory = Control .

L'espace blanc est une propriété assez stable, et ces mêmes existent depuis presque toujours. Même ainsi, Java n'a pas de propriété conforme à la norme Unicode pour ceux-ci, vous devez donc utiliser un code comme celui-ci:

String whitespace_chars =  ""       /* dummy empty string for homogeneity */
                        + "\\u0009" // CHARACTER TABULATION
                        + "\\u000A" // LINE FEED (LF)
                        + "\\u000B" // LINE TABULATION
                        + "\\u000C" // FORM FEED (FF)
                        + "\\u000D" // CARRIAGE RETURN (CR)
                        + "\\u0020" // SPACE
                        + "\\u0085" // NEXT LINE (NEL) 
                        + "\\u00A0" // NO-BREAK SPACE
                        + "\\u1680" // OGHAM SPACE MARK
                        + "\\u180E" // MONGOLIAN VOWEL SEPARATOR
                        + "\\u2000" // EN QUAD 
                        + "\\u2001" // EM QUAD 
                        + "\\u2002" // EN SPACE
                        + "\\u2003" // EM SPACE
                        + "\\u2004" // THREE-PER-EM SPACE
                        + "\\u2005" // FOUR-PER-EM SPACE
                        + "\\u2006" // SIX-PER-EM SPACE
                        + "\\u2007" // FIGURE SPACE
                        + "\\u2008" // PUNCTUATION SPACE
                        + "\\u2009" // THIN SPACE
                        + "\\u200A" // HAIR SPACE
                        + "\\u2028" // LINE SEPARATOR
                        + "\\u2029" // PARAGRAPH SEPARATOR
                        + "\\u202F" // NARROW NO-BREAK SPACE
                        + "\\u205F" // MEDIUM MATHEMATICAL SPACE
                        + "\\u3000" // IDEOGRAPHIC SPACE
                        ;        
/* A \s that actually works for Java’s native character set: Unicode */
String     whitespace_charclass = "["  + whitespace_chars + "]";    
/* A \S that actually works for  Java’s native character set: Unicode */
String not_whitespace_charclass = "[^" + whitespace_chars + "]";

Vous pouvez maintenant l'utiliser whitespace_charclass + "+"comme modèle dans votre fichier replaceAll.


Désolé pour tout ça. Les expressions régulières de Java ne fonctionnent tout simplement pas très bien sur son propre jeu de caractères natif, et vous devez donc vraiment sauter à travers des cerceaux exotiques pour les faire fonctionner.

Et si vous pensez que les espaces blancs sont mauvais, vous devriez voir ce que vous devez faire pour obtenir \wet \benfin se comporter correctement!

Oui, c'est possible, et oui, c'est un désordre hallucinant. C'est même de la charité. Le moyen le plus simple d'obtenir une bibliothèque de regex conforme aux normes pour Java est d'utiliser JNI vers ICU. C'est ce que fait Google pour Android, car OraSun n'est pas à la hauteur.

Si vous ne voulez pas faire cela mais que vous voulez toujours vous en tenir à Java, j'ai une bibliothèque de réécriture de regex frontale que j'ai écrite qui «corrige» les modèles de Java, au moins pour les rendre conformes aux exigences de RL1.2a en UTS # 18, Expressions régulières Unicode .

tchrist
la source
12
Merci pour la tête sur les limitations des regex de Java. +1
ridgerunner
4
Je suis allé voter cette réponse comme utile et j'ai trouvé que j'avais déjà. Alors merci une deuxième fois :)
Andrew Wyld
5
c'est vraiment vieux. est-il correct que cela a été corrigé dans java7 avec l'indicateur UNICODE_CHARACTER_CLASS? (ou en utilisant (? U))
kritzikratzi
5
@tchrist Si cela est corrigé dans java 7+, pourriez-vous mettre à jour la réponse avec la manière désormais correcte de le faire?
beerbajay
7
Avec Java 7+, vous pouvez faire: "(? U) \ s" pour exécuter l'expression régulière avec la conformité aux normes techniques Unicode. Vous pouvez également activer l'indicateur UNICODE_CHARACTER_CLASS lors de la création du modèle. Voici le doc: docs.oracle.com/javase/7/docs/api/java/util/regex/…
Didier A.
15

Pour Java (ni php, ni javascript, ni aucun autre):

txt.replaceAll("\\p{javaSpaceChar}{2,}"," ")
surfealokesea
la source
Les chaînes sont immuables, vous devez donc attribuer le résultat à quelque chose, tel que 'txt = txt.replaceAll ()' Je n'ai pas voté contre votre réponse, mais c'est peut-être pourquoi quelqu'un d'autre l'a fait.
Câblé
6
Je sais que replaceAll renvoie une chaîne la chose importante 4 programmeurs java est \\ p {javaSpaceChar}
surfealokesea
2
La question d'origine a commis l'erreur de ne pas affecter la nouvelle chaîne à une variable. Souligner cette erreur est donc le point le plus important de la réponse.
Câblé
Cela a totalement résolu mon problème dans Groovy! Finalement! J'ai essayé toutes les expressions régulières que j'ai pu trouver qui correspondraient à tous les espaces blancs, y compris NON-BREAK-SPACE (ASCII 160) !!!
Piko
5

quand j'ai envoyé une question à un forum Regexbuddy (application de développement regex), j'ai obtenu une réponse plus exacte à ma question Java:

"Auteur du message: Jan Goyvaerts

En Java, les raccourcis \ s, \ d et \ w incluent uniquement des caractères ASCII. ... Ce n'est pas un bogue en Java, mais simplement l'une des nombreuses choses dont vous devez être conscient lorsque vous travaillez avec des expressions régulières. Pour faire correspondre tous les espaces blancs Unicode ainsi que les sauts de ligne, vous pouvez utiliser [\ s \ p {Z}] en Java. RegexBuddy ne prend pas encore en charge les propriétés spécifiques à Java telles que \ p {javaSpaceChar} (qui correspond exactement aux mêmes caractères que [\ s \ p {Z}]).

... \ s \ s correspondra à deux espaces, si l'entrée est uniquement ASCII. Le vrai problème vient du code de l'OP, comme le souligne la réponse acceptée à cette question. "

Tuomas
la source
3
[\s\p{z}]omet le caractère Unicode "ligne suivante" U + 0085. Utilisez [\s\u0085\p{Z}].
Robert Tupelo-Schneck
3

Semble fonctionner pour moi:

String s = "  a   b      c";
System.out.println("\""  + s.replaceAll("\\s\\s", " ") + "\"");

imprimera:

" a  b   c"

Je pense que vous aviez l'intention de faire ceci au lieu de votre code:

Pattern whitespace = Pattern.compile("\\s\\s");
Matcher matcher = whitespace.matcher(s);
String result = "";
if (matcher.find()) {
    result = matcher.replaceAll(" ");
}

System.out.println(result);
Mihai Toader
la source
3

Pour vos besoins, vous pouvez utiliser cet extrait de code:

import org.apache.commons.lang3.StringUtils;

StringUtils.normalizeSpace(string);

Cela normalisera l'espacement en simple et supprimera également les espaces blancs de départ et de fin.

String sampleString = "Hello    world!";
sampleString.replaceAll("\\s{2}", " "); // replaces exactly two consecutive spaces
sampleString.replaceAll("\\s{2,}", " "); // replaces two or more consecutive white spaces
Rashid Mv
la source
1
Pattern whitespace = Pattern.compile("\\s\\s");
matcher = whitespace.matcher(modLine);

boolean flag = true;
while(flag)
{
 //Update your original search text with the result of the replace
 modLine = matcher.replaceAll(" ");
 //reset matcher to look at this "new" text
 matcher = whitespace.matcher(modLine);
 //search again ... and if no match , set flag to false to exit, else run again
 if(!matcher.find())
 {
 flag = false;
 }
}
Mike
la source
3
Mike, bien que j'apprécie que vous ayez pris le temps de répondre, cette question a été résolue il y a plusieurs mois. Il n'est pas nécessaire de répondre à des questions aussi anciennes que celle-ci.
6
Si quelqu'un peut montrer une solution différente et meilleure, il est parfaitement légitime de répondre à de vieilles questions.
james.garriss
1

Java a évolué depuis que ce problème a été soulevé pour la première fois. Vous pouvez faire correspondre toutes sortes de caractères d'espacement Unicode en utilisant le \p{Zs}groupe.

Ainsi, si vous souhaitez remplacer un ou plusieurs espaces exotiques par un espace simple, vous pouvez le faire:

String txt = "whatever my string is";
txt.replaceAll("\\p{Zs}+", " ")

Il convient également de savoir, si vous avez utilisé la trim()fonction de chaîne que vous devriez jeter un oeil à la (relativement nouveau) strip(), stripLeading()et des stripTrailing()fonctions sur les chaînes. Le peut vous aider à découper toutes sortes de caractères d'espaces blancs. Pour plus d'informations sur l'espace inclus, consultez la Character.isWhitespace()fonction Java .

Robert
la source
-3

L'utilisation d'espaces dans RE est une douleur, mais je pense qu'ils fonctionnent. Le problème de l'OP peut également être résolu en utilisant StringTokenizer ou la méthode split (). Cependant, pour utiliser RE (décommentez println () pour voir comment le matcher rompt la chaîne), voici un exemple de code:

import java.util.regex.*;

public class Two21WS {
    private String  str = "";
    private Pattern pattern = Pattern.compile ("\\s{2,}");  // multiple spaces

    public Two21WS (String s) {
            StringBuffer sb = new StringBuffer();
            Matcher matcher = pattern.matcher (s);
            int startNext = 0;
            while (matcher.find (startNext)) {
                    if (startNext == 0)
                            sb.append (s.substring (0, matcher.start()));
                    else
                            sb.append (s.substring (startNext, matcher.start()));
                    sb.append (" ");
                    startNext = matcher.end();
                    //System.out.println ("Start, end = " + matcher.start()+", "+matcher.end() +
                    //                      ", sb: \"" + sb.toString() + "\"");
            }
            sb.append (s.substring (startNext));
            str = sb.toString();
    }

    public String toString () {
            return str;
    }

    public static void main (String[] args) {
            String tester = " a    b      cdef     gh  ij   kl";
            System.out.println ("Initial: \"" + tester + "\"");
            System.out.println ("Two21WS: \"" + new Two21WS(tester) + "\"");
}}

Il produit ce qui suit (compilez avec javac et exécutez à l'invite de commande):

% java Two21WS Initial: "ab cdef gh ij kl" Two21WS: "ab cdef gh ij kl"

Manidip Sengupta
la source
8
WTF !? Pourquoi voudriez-vous faire tout cela alors que vous pouvez simplement appeler à la replaceAll()place?
Alan Moore