¿Cómo convierto CamelCase en nombres legibles para humanos en Java?

Me gustaría escribir un método que convierta a CamelCase en un nombre legible para los humanos.

Aquí está el caso de prueba:

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")); } 

Esto funciona con tus testcases:

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

Aquí hay un arnés de prueba:

  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) + "]"); } 

Utiliza la expresión regular coincidente de longitud cero con lookbehind y lookforward para encontrar dónde insertar espacios. Básicamente hay 3 patrones, y utilizo String.format para juntarlos y hacerlos más legibles.

Los tres patrones son:

UC detrás de mí, UC seguido de LC delante de mí

  XMLParser AString PDFLoader /\ /\ /\ 

no-UC detrás de mí, UC delante de mí

  MyClass 99Bottles /\ /\ 

Carta detrás de mí, sin letra delante de mí

  GL11 May5 BFG9000 /\ /\ /\ 

Referencias

  • regular-expressions.info/Lookarounds

Preguntas relacionadas

Usar alternativas de coincidencia de longitud cero para dividir:

  • Regex divide la cuerda pero mantiene los separadores
  • La división Java está comiendo mis personajes

Puedes hacerlo usando org.apache.commons.lang.StringUtils

 StringUtils.join( StringUtils.splitByCharacterTypeCamelCase("ExampleTest"), ' ' ); 

Si no te gustan las expresiones regulares “complicadas” y no te molesta en absoluto la eficiencia, entonces he usado este ejemplo para lograr el mismo efecto en tres etapas.

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

Pasa todos los casos de prueba anteriores, incluidos aquellos con dígitos.

Como digo, esto no es tan bueno como usar una expresión regular en algunos otros ejemplos aquí, pero alguien podría encontrarlo útil.

Puede usar org.modeshape.common.text.Inflector .

Específicamente:

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

Escribe en mayúscula la primera palabra y convierte caracteres de subrayado en espacios y tiras que arrastran “_id” y cualquier token extraíble suministrado.

El artefacto de Maven es: org.modeshape: modeshape-common: 2.3.0.Final

en el repository de JBoss: https://repository.jboss.org/nexus/content/repositories/releases

Aquí está el archivo JAR: https://repository.jboss.org/nexus/content/repositories/releases/org/modeshape/modeshape-common/2.3.0.Final/modeshape-common-2.3.0.Final.jar

La solución ordenada y más corta:

 StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase("yourCamelCaseText"), StringUtils.SPACE)); // Your Camel Case Text 

El siguiente Regex se puede usar para identificar las mayúsculas dentro de las palabras:

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

Coincide con cada letra mayúscula, es decir, éter después de una letra o un dígito que no sea mayúscula o seguido de una letra minúscula y cada dígito después de una letra.

Cómo insertar un espacio antes que ellos está más allá de mis habilidades de Java =)

Editado para incluir el caso de los dígitos y el caso de PDF Loader.

Creo que tendrá que iterar sobre la cadena y detectar los cambios de minúscula a mayúscula, de mayúscula a minúscula, de alfabético a numérico, de numérico a alfabético. En cada cambio que detecte, inserte un espacio con una excepción: en un cambio de mayúscula a minúscula, inserta el espacio de un carácter antes.

Esto funciona en .NET … optimiza a tu gusto. Agregué comentarios para que puedas entender lo que está haciendo cada pieza. (RegEx puede ser difícil de entender)

 public static string SplitCamelCase(string str) { str = Regex.Replace(str, @"([AZ])([AZ][az])", "$1 $2"); // Capital followed by capital AND a lowercase. str = Regex.Replace(str, @"([az])([AZ])", "$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; } 

Para el registro, aquí hay una versión de Scala casi (*) 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 

Una vez comstackdo, se puede usar directamente desde Java si el scala-library.jar correspondiente está en el classpath.

(*) falla para la entrada "GL11Version" para la que devuelve "G L11 Version" .

Tomé Regex de polygenelubricants y lo convertí en un método de extensión en objetos:

  ///  /// Turns a given object into a sentence by: /// Converting the given object into a . /// 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. ///  /// The object to turn into a proper sentence. /// A string representation of the original object that reads like a real sentence. public static string ToProperSentence(this object original) { Regex addSpacesAtCapitalLettersRegEx = new Regex(@"(?<=[AZ])(?=[AZ][az]) | (?<=[^AZ])(?=[AZ]) | (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace); string[] words = addSpacesAtCapitalLettersRegEx.Split(original.ToString()); if (words.Length > 1) { List wordsList = new List { words[0] }; wordsList.AddRange(words.Skip(1).Select(word => word.Equals(word.ToUpper()) ? word : word.ToLower())); words = wordsList.ToArray(); } return string.Join(" ", words); } 

Esto convierte todo en una oración legible. Hace un ToString en el objeto pasado. Luego usa la Regex dada por polygenelubricants para dividir la cadena. Luego, ToLowers cada palabra a excepción de la primera palabra y cualquier acrónimo. Pensé que podría ser útil para alguien allá afuera.

No soy un ninja regex, así que iteraría sobre la cuerda, manteniendo los índices de la posición actual siendo revisados ​​y la posición anterior. Si la posición actual es una letra mayúscula, insertaría un espacio después de la posición anterior e incrementaría cada índice.

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

Puede encadenar los métodos String.underscore (). Humanize () para tomar una cadena CamelCase y convertirla en una cadena legible para humanos.

Intereting Posts