Comment convertir CamelCase en noms lisibles par L'homme en Java?

j'aimerais écrire une méthode qui convertit CamelCase en un nom lisible par les humains.

voici le cas d'essai:

public void testSplitCamelCase() {
    assertEquals("lowercase", splitCamelCase("lowercase"));
    assertEquals("Class", splitCamelCase("Class"));
    assertEquals("My Class", splitCamelCase("MyClass"));
    assertEquals("HTML", splitCamelCase("HTML"));
    assertEquals("PDF Loader", splitCamelCase("PDFLoader"));
    assertEquals("A String", splitCamelCase("AString"));
    assertEquals("Simple XML Parser", splitCamelCase("SimpleXMLParser"));
    assertEquals("GL 11 Version", splitCamelCase("GL11Version"));
}
140
demandé sur Frederik 2010-04-01 14:42:06

12 réponses

cela fonctionne avec vos testcases:

static String splitCamelCase(String s) {
   return s.replaceAll(
      String.format("%s|%s|%s",
         "(?<=[A-Z])(?=[A-Z][a-z])",
         "(?<=[^A-Z])(?=[A-Z])",
         "(?<=[A-Za-z])(?=[^A-Za-z])"
      ),
      " "
   );
}

voici un harnais d'essai:

    String[] tests = {
        "lowercase",        // [lowercase]
        "Class",            // [Class]
        "MyClass",          // [My Class]
        "HTML",             // [HTML]
        "PDFLoader",        // [PDF Loader]
        "AString",          // [A String]
        "SimpleXMLParser",  // [Simple XML Parser]
        "GL11Version",      // [GL 11 Version]
        "99Bottles",        // [99 Bottles]
        "May5",             // [May 5]
        "BFG9000",          // [BFG 9000]
    };
    for (String test : tests) {
        System.out.println("[" + splitCamelCase(test) + "]");
    }

il utilise le regex matching de longueur zéro avec lookbehind et look forward pour trouver où insérer des espaces. Fondamentalement, il existe 3 modèles, et j'utilise String.format pour les mettre ensemble pour le rendre plus lisible.

les trois motifs sont:

UC derrière moi, UC suivi de LC devant moi

  XMLParser   AString    PDFLoader
    /\        /\           /\

non-UC derrière moi, UC devant moi

 MyClass   99Bottles
  /\        /\

lettre derrière moi, non-lettre devant moi

 GL11    May5    BFG9000
  /\       /\      /\

Références

questions connexes

utilisant des lookarounds appariés de longueur nulle à diviser:

304
répondu polygenelubricants 2017-05-23 12:26:21

vous pouvez le faire en utilisant org.apache.commons.lang.StringUtils

StringUtils.join(
     StringUtils.splitByCharacterTypeCamelCase("ExampleTest"),
     ' '
);
97
répondu Ralph 2014-05-07 14:59:39

si vous n'aimez pas les regex" compliqués " et que vous n'êtes pas du tout soucieux d'efficacité, alors j'ai utilisé cet exemple pour obtenir le même effet en trois étapes.

String name = 
    camelName.replaceAll("([A-Z][a-z]+)", " ") // Words beginning with UC
             .replaceAll("([A-Z][A-Z]+)", " ") // "Words" of only UC
             .replaceAll("([^A-Za-z ]+)", " ") // "Words" of non-letters
             .trim();

il satisfait à tous les essais ci-dessus, y compris ceux avec des chiffres.

comme je l'ai dit, ce n'est pas aussi bon que d'utiliser l'une des expressions régulières dans d'autres exemples ici - mais quelqu'un pourrait bien trouver utile.

9
répondu jlb83 2012-01-12 15:13:14

vous pouvez utiliser org.modeshape.commun.texte.Gonfleur .

spécifiquement:

String humanize(String lowerCaseAndUnderscoredWords,
    String... removableTokens) 

capitalise le premier mot et transforme les underscores en espaces et en bandes à la suite de" _id " et de tous les jetons amovibles fournis.

artefact Maven est: org.modeshape:modeshape-commune:2.3.0.Final

sur le dépôt JBoss: https://repository.jboss.org/nexus/content/repositories/releases

voici le fichier JAR: https://repository.jboss.org/nexus/content/repositories/releases/org/modeshape/modeshape-common/2.3.0.Final/modeshape-common-2.3.0.Final.jar

6
répondu Hendy Irawan 2010-12-18 06:35:35

Le pur et le plus court de solution :

StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase("yourCamelCaseText"), StringUtils.SPACE)); // Your Camel Case Text
5
répondu Sahil Chhabra 2017-10-26 04:10:16

le Regex suivant peut être utilisé pour identifier les majuscules à l'intérieur des mots:

"((?<=[a-z0-9])[A-Z]|(?<=[a-zA-Z])[0-9]]|(?<=[A-Z])[A-Z](?=[a-z]))"

correspond à chaque lettre majuscule, c'est-à-dire à l'éther après une lettre ou un chiffre non majuscule ou suivi d'une lettre minuscule et de chaque chiffre après une lettre.

Comment insérer une espace devant eux, au-delà de mes compétences Java =)

modifié pour inclure le boîtier digit et le boîtier PDF.

1
répondu Jens 2010-04-01 10:53:27

je pense que vous devrez itérer sur la chaîne et détecter les changements de minuscules à majuscules, majuscules à minuscules, alphabétiques à numériques, numériques à alphabétiques. Sur chaque changement vous détectez insérer un espace avec une exception cependant: sur un changement de majuscules à minuscules vous insérez l'espace un caractère avant.

1
répondu Felix 2010-04-01 11:06:05

cela fonctionne dans .NET... optimisez à votre goût. J'ai ajouté des commentaires pour que vous puissiez comprendre ce que chaque pièce fait. (RegEx peut être difficile à comprendre)

public static string SplitCamelCase(string str)
{
    str = Regex.Replace(str, @"([A-Z])([A-Z][a-z])", " ");  // Capital followed by capital AND a lowercase.
    str = Regex.Replace(str, @"([a-z])([A-Z])", " "); // Lowercase followed by a capital.
    str = Regex.Replace(str, @"(\D)(\d)", " "); //Letter followed by a number.
    str = Regex.Replace(str, @"(\d)(\D)", " "); // Number followed by letter.
    return str;
}
1
répondu Xinbi 2014-06-12 23:10:47

pour rappel, voici une version Scala presque (*) compatible:

  object Str { def unapplySeq(s: String): Option[Seq[Char]] = Some(s) }

  def splitCamelCase(str: String) =
    String.valueOf(
      (str + "A" * 2) sliding (3) flatMap {
        case Str(a, b, c) =>
          (a.isUpper, b.isUpper, c.isUpper) match {
            case (true, false, _) => " " + a
            case (false, true, true) => a + " "
            case _ => String.valueOf(a)
          }
      } toArray
    ).trim

une fois compilé, il peut être utilisé directement depuis Java si la bibliothèque scala correspondante.jar est dans le chemin de la classe.

( * ) il échoue pour l'entrée "GL11Version" pour laquelle il renvoie "G L11 Version" .

0
répondu gerferra 2011-07-03 06:13:16

j'ai pris la Regex de polygenelubricants et l'ai transformée en une méthode d'extension sur des objets:

    /// <summary>
    /// Turns a given object into a sentence by:
    /// Converting the given object into a <see cref="string"/>.
    /// Adding spaces before each capital letter except for the first letter of the string representation of the given object.
    /// Makes the entire string lower case except for the first word and any acronyms.
    /// </summary>
    /// <param name="original">The object to turn into a proper sentence.</param>
    /// <returns>A string representation of the original object that reads like a real sentence.</returns>
    public static string ToProperSentence(this object original)
    {
        Regex addSpacesAtCapitalLettersRegEx = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z]) | (?<=[^A-Z])(?=[A-Z]) | (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
        string[] words = addSpacesAtCapitalLettersRegEx.Split(original.ToString());
        if (words.Length > 1)
        {
            List<string> wordsList = new List<string> { words[0] };
            wordsList.AddRange(words.Skip(1).Select(word => word.Equals(word.ToUpper()) ? word : word.ToLower()));
            words = wordsList.ToArray();
        }
        return string.Join(" ", words);
    }

cela transforme tout en une phrase lisible. Il fait un ToString sur l'objet passé. Puis il utilise le Regex donné par polygenelubricants pour fendre la corde. Puis il tolère chaque mot sauf pour le premier mot et les acronymes. Pensé qu'il pourrait être utile pour quelqu'un là-bas.

0
répondu vbullinger 2012-08-16 15:58:12

Je ne suis pas un ninja regex, donc je vais itérer sur la chaîne, en gardant les index de la position courante étant vérifiée et la position précédente. Si le poste actuel est une lettre majuscule, j'insérerais un espace après le poste précédent et incrémenterais chaque index.

-1
répondu Joel 2010-06-04 00:20:26

http://code.google.com/p/inflection-js/

vous pouvez enchaîner la chaîne .souligner.)(humanize () méthodes pour prendre une chaîne de caractères CamelCase et la convertir en une chaîne lisible par l'humain.

-3
répondu BeesonBison 2010-05-03 14:43:38