J'aimerais écrire une méthode qui convertit CamelCase en un nom lisible par l'homme.
Voici le cas de test:
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"));
}
Cela fonctionne avec vos cas de test:
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 de test:
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 une expression rationnelle de longueur nulle avec lookbehind et lookforward pour trouver où insérer des espaces. Fondamentalement, il existe 3 modèles, et j'utilise String.format
de les assembler pour le rendre plus lisible.
Les trois modèles sont:
XMLParser AString PDFLoader
/\ /\ /\
MyClass 99Bottles
/\ /\
GL11 May5 BFG9000
/\ /\ /\
Utilisation de comparaisons de longueur nulle pour la scission:
Vous pouvez le faire en utilisant org.Apache.commons.lang.StringUtils
StringUtils.join(
StringUtils.splitByCharacterTypeCamelCase("ExampleTest"),
' '
);
La solution soignée et plus courte:
StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase("yourCamelCaseText"), StringUtils.SPACE)); // Your Camel Case Text
Si vous n'aimez pas les expressions rationnelles "compliquées" et si vous ne vous souciez pas de l'efficacité, j'ai utilisé cet exemple pour obtenir le même effet en trois étapes.
String name =
camelName.replaceAll("([A-Z][a-z]+)", " $1") // Words beginning with UC
.replaceAll("([A-Z][A-Z]+)", " $1") // "Words" of only UC
.replaceAll("([^A-Za-z ]+)", " $1") // "Words" of non-letters
.trim();
Il passe tous les tests ci-dessus, y compris ceux avec des chiffres.
Comme je l'ai dit, cela ne vaut pas l'utilisation de l'expression régulière unique dans d'autres exemples ici - mais quelqu'un pourrait trouver cela utile.
Vous pouvez utiliser org.modeshape.common.text.Inflector .
Plus précisément:
String humanize(String lowerCaseAndUnderscoredWords, String... removableTokens)
Met en majuscule le premier mot et transforme les traits de soulignement en espaces et supprime "_id" et tous les jetons amovibles fournis.
Artefact Maven est: org.modeshape: modeshape-common: 2.3.0.Final
sur le référentiel 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
Les expressions rationnelles suivantes peuvent être utilisées pour identifier les majuscules dans les mots:
"((?<=[a-z0-9])[A-Z]|(?<=[a-zA-Z])[0-9]]|(?<=[A-Z])[A-Z](?=[a-z]))"
Il correspond à chaque lettre majuscule, c'est-à-dire l'éther après une lettre non majuscule ou un chiffre ou suivi d'une lettre minuscule et de chaque chiffre après une lettre.
Comment insérer un espace devant eux est au-delà de mon Java compétences =)
Edité pour inclure le cas numérique et le PDF cas du chargeur.
Je pense que vous devrez parcourir la chaîne et détecter les changements de minuscule à majuscule, de majuscule à minuscule, alphabétique à numérique, numérique à alphabétique. Lors de chaque modification, vous détectez l'insertion d'un espace, à une exception près: lorsque vous passez d'une majuscule à une minuscule, vous insérez l'espace avant un caractère.
Cela fonctionne en .NET ... optimisez à votre convenance. 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])", "$1 $2"); // Capital followed by capital AND a lowercase.
str = Regex.Replace(str, @"([a-z])([A-Z])", "$1 $2"); // Lowercase followed by a capital.
str = Regex.Replace(str, @"(\D)(\d)", "$1 $2"); //Letter followed by a number.
str = Regex.Replace(str, @"(\d)(\D)", "$1 $2"); // Number followed by letter.
return str;
}
J'ai pris le regex de polygenelubricants et l'ai transformé en une méthode d'extension sur les 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é. Ensuite, il utilise la regex donnée par les polygenelubricants pour scinder la chaîne. Ensuite, il perd chaque mot, à l'exception du premier mot et des acronymes. Je pensais que cela pourrait être utile pour quelqu'un.
Pour mémoire, voici une version presque (*) compatible Scala version:
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 à partir de Java si le fichier scala-library.jar correspondant se trouve dans le chemin de classe.
(*) il échoue pour l'entrée "GL11Version"
pour lequel il retourne "G L11 Version"
.