94 votes

RegEx pour séparer camelCase ou TitleCase (advanced)

J'ai trouvé un brillant RegEx extraire le cadre d'un camelCase ou TitleCase expression.

 (?<!^)(?=[A-Z])

Il fonctionne comme prévu:

  • valeur> valeur
  • camelValue -> chameau / Valeur
  • TitleValue -> Titre / Valeur

Par exemple avec Java:

String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
//words equals words = new String[]{"lorem","Ipsum"}

Mon problème est qu'il ne fonctionne pas dans certains cas:

  • Cas 1: VALEUR -> V / A / L / U / E
  • Cas 2: eclipseRCPExt -> eclipse / R / C / P / Ext

À mon avis, le résultat devrait être:

  • Cas 1: VALEUR
  • Cas 2: eclipse / RCP / Ext

En d'autres termes, étant donné n majuscule des caractères:

  • si les n caractères sont suivis par les minuscules caractères, les groupes devraient être: (n-1 caractères) / (n-ème char + bas caractères)
  • si les n caractères sont à la fin, le groupe devrait être: (n caractères).

Aucune idée sur la façon d'améliorer cette regex?

121voto

NPE Points 169956

La suite de regex fonctionne pour tous les exemples ci-dessus:

public static void main(String[] args)
{
    for (String w : "camelValue".split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")) {
        System.out.println(w);
    }
}   

Il fonctionne en forçant le négatif lookbehind non seulement ignorer correspond au début de la chaîne, mais aussi d'ignorer les matchs où une lettre majuscule est précédée par une autre lettre majuscule. Cette traite les cas comme "VALEUR".

La première partie de l'expression régulière sur son propre échoue sur "eclipseRCPExt" en omettant de scission entre "RPC" et "Ext". C'est l'objet de la clause: (?<!^)(?=[A-Z][a-z]. Cette clause permet à un split avant chaque lettre majuscule, qui est suivie d'une lettre minuscule, sauf au début de la chaîne.

98voto

ridgerunner Points 14773

Il semble que vous êtes faire cela d'autant plus compliqué qu'il doit être. Pour camelCase, le partage de l'emplacement est tout simplement n'importe où une lettre majuscule suit immédiatement une lettre minuscule:

(?<=[a-z])(?=[A-Z])

Voici comment cette regex répartit les données de l'exemple:

  • value -> value
  • camelValue -> camel / Value
  • TitleValue -> Title / Value
  • VALUE -> VALUE
  • eclipseRCPExt -> eclipse / RCPExt

La seule différence à partir de votre sortie désirée est avec l' eclipseRCPExt, qui je dirais est correctement affichée ici.

Addendum - version Améliorée

Note: Cette réponse a récemment obtenu un upvote et j'ai réalisé qu'il y est une meilleure façon...

Par l'ajout d'une deuxième variante de ce qui précède regex, toutes les OP les cas de test sont correctement séparées.

(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])

Voici comment l'amélioration de la regex divise les données d'exemple:

  • value -> value
  • camelValue -> camel / Value
  • TitleValue -> Title / Value
  • VALUE -> VALUE
  • eclipseRCPExt -> eclipse / RCP / Ext

Edit:20130824 Ajoutée version améliorée de manipuler RCPExt -> RCP / Ext des cas.

38voto

YMomb Points 1105

Une autre solution consisterait à utiliser une méthode dédiée dans commons-lang : StringUtils # splitByCharacterTypeCamelCase

10voto

deadlydog Points 1840

Je ne pouvais pas obtenir aix la solution de travail (et il ne fonctionne pas sur RegExr soit), alors je suis venu avec moi, que je l'ai testé et semble faire exactement ce que vous cherchez:

((^[a-z]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($))))

et voici un exemple d'utilisation:

; Regex Breakdown:  This will match against each word in Camel and Pascal case strings, while properly handling acrynoms.
;   (^[a-z]+)                       Match against any lower-case letters at the start of the string.
;   ([A-Z]{1}[a-z]+)                Match against Title case words (one upper case followed by lower case letters).
;   ([A-Z]+(?=([A-Z][a-z])|($)))    Match against multiple consecutive upper-case letters, leaving the last upper case letter out the match if it is followed by lower case letters, and including it if it's followed by the end of the string.
newString := RegExReplace(oldCamelOrPascalString, "((^[a-z]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($))))", "$1 ")
newString := Trim(newString)

Ici, je suis en séparant chaque mot d'un espace, alors voici quelques exemples de la façon dont la chaîne est transformé:

  • ThisIsATitleCASEString => Ceci Est Un Titre de CAS de la Chaîne
  • andThisOneIsCamelCASE => et C'Est Un Chameau CAS

Cette solution ci-dessus n'est que le post original demande, mais j'ai aussi besoin de regex pour trouver chameau et pascal chaînes qui inclus de nombres, de sorte que j'en suis venu à cette variation d'inclure les numéros:

((^[a-z]+)|([0-9]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($)|([0-9]))))

et un exemple d'utilisation:

; Regex Breakdown:  This will match against each word in Camel and Pascal case strings, while properly handling acrynoms and including numbers.
;   (^[a-z]+)                               Match against any lower-case letters at the start of the command.
;   ([0-9]+)                                Match against one or more consecutive numbers (anywhere in the string, including at the start).
;   ([A-Z]{1}[a-z]+)                        Match against Title case words (one upper case followed by lower case letters).
;   ([A-Z]+(?=([A-Z][a-z])|($)|([0-9])))    Match against multiple consecutive upper-case letters, leaving the last upper case letter out the match if it is followed by lower case letters, and including it if it's followed by the end of the string or a number.
newString := RegExReplace(oldCamelOrPascalString, "((^[a-z]+)|([0-9]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($)|([0-9]))))", "$1 ")
newString := Trim(newString)

Et voici quelques exemples de la façon dont une chaîne de caractères avec des chiffres est transformé avec cette regex:

  • myVariable123 => ma Variable 123
  • my2Variables => mes 2 Variables
  • The3rdVariableIsHere => Les 3 rdVariable Est Ici
  • 12345NumsAtTheStartIncludedToo => 12345 Nums Au Début Aussi Inclus

6voto

Je pense que c'est plus simple:

Diviser après une lettre minuscule suivie d'une lettre majuscule ou après une lettre suivie d'une lettre majuscule suivie d'une lettre minuscule.

 public static String unCamelCase(String s) {
    return s.replaceAll("(?<=\\p{Ll})(?=\\p{Lu})|(?<=\\p{L})(?=\\p{Lu}\\p{Ll})", " ");
}
 

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