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

时间:2010-04-01 10:42:06

标签: java regex string camelcasing humanize

我想编写一个将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"));
}

12 个答案:

答案 0 :(得分:313)

这适用于您的测试用例:

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

它使用零长度匹配正则表达式与lookbehind和lookforward来查找插入空格的位置。基本上有3种模式,我使用String.format将它们组合在一起以使其更具可读性。

这三种模式是:

UC在我身后,UC在我面前跟着LC

  XMLParser   AString    PDFLoader
    /\        /\           /\

非UC在我身后,UC在我面前

 MyClass   99Bottles
  /\        /\

在我身后的信,在我面前的非信件

 GL11    May5    BFG9000
  /\       /\      /\

参考

相关问题

使用零长度匹配的外观来分割:

答案 1 :(得分:102)

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

执行此操作
StringUtils.join(
     StringUtils.splitByCharacterTypeCamelCase("ExampleTest"),
     ' '
);

答案 2 :(得分:10)

整洁而简短的解决方案:

    private void btnSeparate_Click(object sender, EventArgs e)
    {
        // Get the sentence from the text box
        string sentence = txtWords.Text;
        int upperCase; // to hold the index of an uppercase letter

        foreach (char up in sentence)
        {

            if (char.IsUpper(up))
            {

                // Find the index of the uppercase letter
                upperCase = sentence.IndexOf(up);

                // Insert a space at the appropriate index
                sentence = sentence.Insert(upperCase, " ");
            }
        }
        // Make all the letters lowercase
        sentence = sentence.ToLower();
        // Capitalize the first letter of the sentence.
        sentence = sentence[1].ToString().ToUpper() + sentence.Substring(2);

        // Display the separeted words
        lblSeparatedWords.Text = sentence;

    }
}

答案 3 :(得分:9)

如果你不喜欢“复杂”的正则表达式,并且对效率一点也不感兴趣,那么我就用这个例子来分三个阶段达到同样的效果。

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

它传递了上面的所有测试用例,包括带有数字的测试用例。

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

答案 4 :(得分:6)

您可以使用org.modeshape.common.text.Inflector

具体做法是:

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

将第一个单词大写并将下划线转换为空格并删除尾随“_id”和任何提供的可移动标记。

Maven工件是: org.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

答案 5 :(得分:1)

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

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

它匹配每个大写字母,即非大写字母或数字之后的以太符号,或后跟小写字母和字母后的每个数字。

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

编辑包含数字案例和PDF Loader案例。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

这适用于.NET ...根据您的喜好进行优化。我添加了评论,以便您了解每件作品的作用。 (RegEx可能很难理解)

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

答案 8 :(得分:0)

对于记录,这是一个几乎(*)兼容的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中使用。

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

答案 9 :(得分:0)

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

    /// <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。然后它使用polygenelubricants给出的正则表达式来分割字符串。然后它除了第一个单词和任何首字母缩略词之外的每个单词。认为它可能对那里的人有用。

答案 10 :(得分:-1)

我不是一个正则表达式的忍者,所以我会迭代字符串,保持当前位置的索引被检查&amp;以前的位置。如果当前位置是大写字母,我会在前一个位置后插入一个空格并递增每个索引。

答案 11 :(得分:-3)

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

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