简体   繁体   English

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

[英]How do I convert CamelCase into human-readable names in Java?

I'd like to write a method that converts CamelCase into a human-readable name.我想编写一个将 CamelCase 转换为人类可读名称的方法。

Here's the test case:这是测试用例:

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

This works with your 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])"
      ),
      " "
   );
}

Here's a test harness:这是一个测试工具:

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

It uses zero-length matching regex with lookbehind and lookforward to find where to insert spaces.它使用零长度匹配正则表达式与后视和前瞻来查找插入空格的位置。 Basically there are 3 patterns, and I use String.format to put them together to make it more readable.基本上有 3 种模式,我使用String.format将它们放在一起以使其更具可读性。

The three patterns are:这三种模式是:

UC behind me, UC followed by LC in front of me UC在我身后,UC跟在我前面的LC

  XMLParser   AString    PDFLoader
    /\        /\           /\

non-UC behind me, UC in front of me非UC在我身后,UC在我面前

 MyClass   99Bottles
  /\        /\

Letter behind me, non-letter in front of me我身后的信,我面前的非信

 GL11    May5    BFG9000
  /\       /\      /\

References参考

Related questions相关问题

Using zero-length matching lookarounds to split:使用零长度匹配环视进行拆分:

You can do it using org.apache.commons.lang.StringUtils你可以使用org.apache.commons.lang.StringUtils

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

简洁而简短的解决方案:

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

If you don't like "complicated" regex's, and aren't at all bothered about efficiency, then I've used this example to achieve the same effect in three stages.如果您不喜欢“复杂”的正则表达式,并且根本不关心效率,那么我已经使用这个示例在三个阶段实现了相同的效果。

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

It passes all the test cases above, including those with digits.它通过了上面的所有测试用例,包括那些带有数字的测试用例。

As I say, this isn't as good as using the one regular expression in some other examples here - but someone might well find it useful.正如我所说,这不如在其他一些示例中使用 one 正则表达式好 - 但有人可能会发现它很有用。

You can use org.modeshape.common.text.Inflector .您可以使用org.modeshape.common.text.Inflector

Specifically:具体来说:

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

Capitalizes the first word and turns underscores into spaces and strips trailing "_id" and any supplied removable tokens.将第一个单词大写并将下划线变成空格并去除尾随“_id”和任何提供的可移动标记。

Maven artifact is: org.modeshape:modeshape-common:2.3.0.Final Maven 工件是: org.modeshape:modeshape-common:2.3.0.Final

on JBoss repository: https://repository.jboss.org/nexus/content/repositories/releases在 JBoss 存储库上: https : //repository.jboss.org/nexus/content/repositories/releases

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

This works in .NET... optimize to your liking.这适用于 .NET...根据您的喜好进行优化。 I added comments so you can understand what each piece is doing.我添加了评论,以便您可以了解每件作品在做什么。 (RegEx can be hard to understand) (正则表达式可能很难理解)

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

The following Regex can be used to identify the capitals inside words:以下正则表达式可用于识别单词中的大写字母:

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

It matches every capital letter, that is ether after a non-capital letter or digit or followed by a lower case letter and every digit after a letter.它匹配每个大写字母,即在非大写字母或数字之后的以太或后跟小写字母和字母之后的每个数字。

How to insert a space before them is beyond my Java skills =)如何在它们之前插入一个空格超出了我的 Java 技能 =)

Edited to include the digit case and the PDF Loader case.编辑以包括数字案例和 PDF 加载程序案例。

I think you will have to iterate over the string and detect changes from lowercase to uppercase, uppercase to lowercase, alphabetic to numeric, numeric to alphabetic.我认为您必须遍历字符串并检测从小写到大写、大写到小写、字母到数字、数字到字母的变化。 On every change you detect insert a space with one exception though: on a change from upper- to lowercase you insert the space one character before.在每次更改时,您检测到插入一个空格,但有一个例外:在从大写到小写的更改中,您在前一个字符插入空格。

I took the Regex from polygenelubricants and turned it into an extension method on objects:我从 polygenelubricants 中获取了 Regex 并将其转换为对象的扩展方法:

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

This turns everything into a readable sentence.这将所有内容都变成了一个可读的句子。 It does a ToString on the object passed.它对传递的对象执行 ToString。 Then it uses the Regex given by polygenelubricants to split the string.然后它使用 polygenelubricants 给出的 Regex 来拆分字符串。 Then it ToLowers each word except for the first word and any acronyms.然后它降低除第一个单词和任何首字母缩略词之外的每个单词。 Thought it might be useful for someone out there.认为它可能对那里的人有用。

For the record, here is an almost (*) compatible Scala version:作为记录,这里有一个几乎 (*) 兼容的 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

Once compiled it can be used directly from Java if the corresponding scala-library.jar is in the classpath.编译后,如果相应的 scala-library.jar 位于类路径中,则可以直接从 Java 中使用它。

(*) it fails for the input "GL11Version" for which it returns "G L11 Version" . (*) 对于返回"G L11 Version" "GL11Version"的输入"GL11Version"失败。

I'm not a regex ninja, so I'd iterate over the string, keeping the indexes of the current position being checked & the previous position.我不是正则表达式忍者,所以我会遍历字符串,保持当前位置的索引被检查和前一个位置。 If the current position is a capital letter, I'd insert a space after the previous position and increment each index.如果当前位置是大写字母,我会在前一个位置后插入一个空格并增加每个索引。

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

You could chain the String.underscore().humanize() methods to take a CamelCase string and convert it into a human readable string.您可以链接String.underscore().humanize()方法以获取 CamelCase 字符串并将其转换为人类可读的字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM