IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Java Regex Majuscules et pluriels


Sujet :

Langage Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 16
    Points : 13
    Points
    13
    Par défaut Java Regex Majuscules et pluriels
    Bonjour,

    Je débute en regex et j'ai du mal à en définir une simple (à priori ) en Java.
    J'utilise un replaceAll(monNewMotif) pour mettre des mots en majuscules dans une chaine.
    Je crée donc un Pattern monMotif et un Matcher maChaine ; monMotif étant une regex. Ce qui donne ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    import java.util.regex.*;
     
    String monMotif = "allumette";
    String maChaine = "une allumette de la boite d'allumettes";
    String monNewMotif = monMotif.toUpperCase();
     
    Pattern pattern = Pattern.compile(monMotif);
    Matcher matcher = pattern.matcher(maChaine);
    String s = matcher.replaceAll(monNewMotif);
    System.out.println(s);
    // Affiche "une ALLUMETTE de la boite d'allumettes"
    Le premier mot "allumette" est bien remplacé mais pas le second qui est au pluriel.

    La chaine pourrait aussi être "Allumette en peuplier", c'est-à-dire avec le mot du motif qui pourrait commencer par une majuscule.

    J'ai fait le choix de mettre les motifs en minuscules mais les chaines de caractères me sont imposées.

    Je dois donc définir une regex à envoyer dans le Pattern qui puisse gérer :

    Première lettre des mots de la chaine pouvant être en majuscule ou en minuscule.
    Dernière lettre des mots de la chaine pouvant être au pluriel : s|S|x|X

    J'ai essayé ceci avec un pluriel en fin de chaine :

    "^([a-zA-Zéèêïà]{1})([\\w]+)([sSxX]{1})$"

    Mais cela ne fonctionne pas

    Je suis sûr qu'il y en a qui font ça les mains dans le dos

    Y aurait-il une bonne âme parmi vous qui pourrait m'aider

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Déjà, tu peux simplifier la problématique de la majuscule en utilisant une expression non sensible à la casse (Pattern.compile( motif , Pattern.CASE_INSENSITIVE).
    Ensuite, le problème du pluriel est plus complexe que d'avoir un s ou un x à la fin (bois au plurier = bois, gaz est forcément au pluriel donc pluriel = gaz). Mais pour régler ton problème particulier, on peut utiliser le pattern (?!s), qui signifie "qui n'est pas suivi de s".

    Donc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    String monMotif = "allumette";
    String monNewMotif = monMotif.toUpperCase();
     
    Pattern pattern = Pattern.compile(monMotif+"(?!s)", Pattern.CASE_INSENSITIVE); // le motif qui n'est pas suivi de s, quelle que soit la casse
    //Pattern pattern = Pattern.compile(monMotif+"(?![sx])", Pattern.CASE_INSENSITIVE); // le motif qui n'est pas suivi de s ou de x, quelle que soit la casse 
     
    System.out.println(pattern.matcher("une allumette de la boite d'allumettes").replaceAll(monNewMotif));
    System.out.println(pattern.matcher("Allumette en peuplier").replaceAll(monNewMotif));
    A noter que monMotif ne doit pas contenir de caractères spéciaux au sens "expressions régulières" pour que ça fonctionne (normalement un mot français n'en contient pas). On peut échaper le montif avec la méthode Pattern.quote() au besoin.

    Ton expression "^([a-zA-Zéèêïà]{1})([\\w]+)([sSxX]{1})$" :
    • le ^ signifie le début de la chaîne et le $ la fin de la chaîne : donc ton expression ne fonctionne que pour l'ensemble d'une chaîne. Comme il n'y a aucune espace, alors il faudrait que la chaîne soit sans espace pour qu'il y ait remplacement
    • le groupe à la fin ([sSxX]{1}) indique qu'il faut qu'il y ait un s ou x (minuscule ou majuscule), alors que tu voudrais faire l'inverse
    • Il est inutile de préciser {1} : [sSxX] signifie une fois l'un des caractères de la classe
    • il n'est pas utile d'encadrer un \\w : \\w+ est suffisant au lieu de ([\\w])+.


    De plus, ton expression est générale : \\w veut dire tous les caractères non espace. Donc tu es parti pour remplacer tous les mots par allumette (sauf ceux au pluriel). Ce n'est probablement pas ce que tu veux faire...
    Quoiqu'il en soit, on peut remplacer tous les mots sauf les mots terminant par s ou par x comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    final static Pattern PATTERN = Pattern.compile("([^sx'\\s])++(?![sx])", Pattern.CASE_INSENSITIVE);
    private static String replaceAllSingular(String string) {
     
       StringBuffer sb=new StringBuffer();
       Matcher matcher = PATTERN.matcher(string);
       while(matcher.find()) {
          matcher.appendReplacement(sb, matcher.group(0).toUpperCase());
       }
       matcher.appendTail(sb);
       return sb.toString();
    }
    Avec l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    System.out.println(replaceAllSingular("une allumette de la boite d'allumettes"));
    System.out.println(replaceAllSingular("Allumette en peuplier"));
    Qui donne donc :
    UNE ALLUMETTE DE LA BOITE D'allumettes
    ALLUMETTE EN PEUPLIER
    • "([^sx'\\s])" : un caractère sauf s, x, l'apostrophe (enfin la quote exactement) ou l'espace
    • "([^sx'\\s])+" : une suite (au moins un) de caractères sauf s, x, l'apostrophe (enfin la quote exactement) ou l'espace
    • Cette expression étant gourmande (greedy), toute la chaine est consommée puis si ça ne matche pas on recule et on reteste, et ainsi de suite. Conséquence, le mot "allumett" matcherait puisque c'est un mot non suivi d'un s ou d'un x (suivi par un e) et on obtiendrait en résultat "UNE ALLUMETTE DE LA BOITE D'ALLUMETTes". c'est pourquoi j'ajoute un second + pour rendre l'expression possessive.
    • le tout suivi de notre motif (?![sx]) non suivi d'un s ou d'un x
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 16
    Points : 13
    Points
    13
    Par défaut
    Salut Joël,

    Merci pour ton aide rapide et précise

    MAJUSCULES
    Pattern.CASE_INSENSITIVE, c'est magique c'est exactement ce que je cherchais.
    J'ai aussi lu qu'on pouvait mettre (?i) dans le motif et que cela permettait de limiter la porter du modificateur à tous les caractères à droite.
    Je me dis que cela pourra me servir dans d'autres circonstances.
    Problème résolu.

    PLURIELS
    Effectivement, bois et gaz sont des cas particuliers que je vais éviter pour l'instant.

    REGEX "([^sx'\\s])++(?![sx])"
    (?!s)
    Je souhaite mettre en majuscules certains mots d'une chaine. Ces mots peuvent apparaitre au singulier ou au pluriel dans la chaine comme : allumette/allumettes ou oeuf/oeufs.
    J'ai donc fait une boucle qui scanne tous les mots de la liste de motifs. Et ça fonctionne . J'y mets actuellement les pluriels et les singuliers.
    Si le motif est (monMotif+"(?!s)", cela ne va sélectionner que les mots au singulier dans la chaine.
    Si maChaine = "une allumette de la boite d'allumettes" et monMotif = "allumette", je souhaite obtenir : "une ALLUMETTE de la boite d'ALLUMETTES".
    C'est pour cela que j'avais tenter avec ([sSxX]{1})$" mais peut-être aurais je pu mettre monMotif+"([sSxX]?)$"

    (?![sx])
    "le tout suivi de notre motif (?![sx]) non suivi d'un s ou d'un x"
    Comment doit-on comprendre : Le motif permettra de choisir :
    1) les mots de la chaine qui ne sont pas suivi d'un s ou d'un x ? "ALLUMETTE" oui mais pas "allumettes" dans la chaine ?
    2) les motifs qui peuvent éventuellement être complétés par un s ou un x ? "ALLUMETTE" et "ALLUMETTES" ?
    Quand tu écris "UNE ALLUMETTE DE LA BOITE D'ALLUMETTes", j'en conclue que c'est (1) qui fonctionne alors que j'ai plutôt besoin du (2).

    ^sx : pas s et pas x. OK mais pourquoi cette restriction ? "saumon" et "saumons" font partie de mes motifs mais pas saucisse(s).
    ([^sx'\\s])+ : OK compris.
    ([^sx'\\s])++ : possessive OK compris. Les regex sont plus faciles à lire qu'à écrire.

    MOTS PARTICULIERS
    Je viens de découvrir un piège.
    J'ai un des motifs qui est le suivant "oeuf".
    Dans la chaine à traiter, j'ai entre autre ",^FDBoeuf, carotte, petit pois".
    J'obtiens donc naturellement ",^FDBOEUF, carotte, petit pois".
    Sauf que "boeuf" ne fait pas partie de mes motifs possibles, "oeuf" oui.
    Je vais devoir prévoir une liste d'exclusions, de conditions à l'utilisation de la liste des motifs.
    Je n'avais pas prévu ce type de cas. Je n'ai pas encore trouvé mais je m'en sortirai peut-être avec une boucle.

    Merci pour ton aide. Tu m'as déjà bien aidé . J'ai encore un peu de mal avec les pluriels en regex. Mais comme j'écrivais les regex sont plus faciles à lire qu'à écrire

Discussions similaires

  1. Convertir C# RegEx vers Java RegEx
    Par hbespoir2003 dans le forum C#
    Réponses: 6
    Dernier message: 19/06/2010, 11h38
  2. Convert C# RegEx to Java RegEx
    Par hbespoir2003 dans le forum Développement Web en Java
    Réponses: 0
    Dernier message: 17/06/2010, 23h31
  3. Java Regex remplacer un entier dans une chaine
    Par snoops2009 dans le forum Collection et Stream
    Réponses: 7
    Dernier message: 17/03/2009, 19h37
  4. [RegEx] regex majuscule avec accent
    Par zobsystem dans le forum Langage
    Réponses: 5
    Dernier message: 22/06/2007, 16h29
  5. java regex (suite)
    Par sroux dans le forum Langage
    Réponses: 4
    Dernier message: 21/06/2006, 14h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo