如何在 Java 中将 CamelCase 转换为人类可读的名称?

我想写一个方法,将 CamelCase 转换成一个人类可读的名称。

以下是测试案例:

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"));
}
75294 次浏览

下面的正则表达式可用于识别单词中的大写字母:

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

它匹配每个大写字母,也就是在非大写字母或数字之后,或者在小写字母之后,以及在字母之后的每个数字。

如何在它们之前插入一个空格超出了我的 Java 技能 =)

编辑,以包括数字案件和 PDF 装载机案件。

我认为您必须遍历字符串并检测从小写到大写、从大写到小写、从字母到数字、从数字到字母的变化。在每次检测到更改时,插入一个空格,但有一个例外: 在从大写到小写的更改中,在空格之前插入一个字符。

这对您的测试用例有效:

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

下面是一个测试工具:

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

它使用零长度匹配正则表达式,带有后视和前视功能,以查找插入空格的位置。基本上有3种模式,我使用 String.format把它们放在一起,使其更具可读性。

这三种模式是:

卧底在我后面,卧底在我前面

  XMLParser   AString    PDFLoader
/\        /\           /\

非卧底在我后面,卧底在我前面

 MyClass   99Bottles
/\        /\

信在我身后,非信在我身前

 GL11    May5    BFG9000
/\       /\      /\

参考文献

相关问题

使用零长度匹配查找来分割:

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

您可以链接 Underscore () . Humanize ()方法以获取 CamelCase 字符串并将其转换为人类可读的字符串。

我不是一个正则表达式忍者,所以我会遍历字符串,保持当前位置的索引被检查和前一个位置。如果当前位置是大写字母,我会在前一个位置后面插入一个空格,并对每个索引增量。

你可以使用 Org.modeshape.common.text

具体来说:

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

将第一个单词大写,并将下划线转换为尾随“ _ id”的空格和条带以及任何提供的可移动标记。

玛文的藏物是: Modeshape: modeshape-common: 2.3.0. Final

关于 JBoss 存储库: https://repository.jboss.org/nexus/content/repositories/releases

这是 JAR 文件: https://repository.jboss.org/nexus/content/repositories/releases/org/modeshape/modeshape-common/2.3.0.Final/modeshape-common-2.3.0.Final.jar

为了便于记录,这里有一个几乎(*)兼容的 Scala 版本:

  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

一旦编译完成,如果对应的 scala-library. jar 在类路径中,就可以直接从 Java 使用它。

(*)对于返回 "G L11 Version"的输入 "GL11Version"失败。

如果您不喜欢“复杂”的正则表达式,并且完全不关心效率,那么我已经使用这个示例在三个阶段实现了相同的效果。

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();

它通过了上面的所有测试用例,包括那些带有数字的测试用例。

正如我所说的,这不如在这里的其他示例中使用一个正则表达式那么好——但是有人可能会发现它很有用。

我从多基因润滑剂中提取了正则表达式,并将其转化为对象的扩展方法:

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

这样一来,所有的东西都变成了一个可读的句子。它对传递的对象执行 ToString 操作。然后,它使用由多基因润滑剂提供的正则表达式来分割字符串。然后它 ToLowers 每个单词除了第一个单词和任何首字母缩略词。我觉得可能对外面的某个人有用。

你可以使用 org.apache.commons.lang.StringUtils

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

这个可以用。NET... 优化到您的喜好。我添加了评论,这样你就可以理解每一篇文章在做什么。(正则表达式可能很难理解)

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

简洁明了的解决办法是:

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