167

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

12 に答える 12

352

これはテストケースで機能します:

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読みやすいようにまとめて使っています。

3つのパターンは次のとおりです。

後ろに UC、前に LC の後に UC

  XMLParser   AString    PDFLoader
    /\        /\           /\

後ろに非UC、前にUC

 MyClass   99Bottles
  /\        /\

後ろは手紙、前は手紙じゃない

 GL11    May5    BFG9000
  /\       /\      /\

参考文献

関連する質問

長さがゼロの一致するルックアラウンドを使用して分割します。

于 2010-04-01T11:35:13.533 に答える
139

を使用してそれを行うことができますorg.apache.commons.lang.StringUtils

StringUtils.join(
     StringUtils.splitByCharacterTypeCamelCase("ExampleTest"),
     ' '
);
于 2013-09-19T05:57:31.230 に答える
11

「複雑な」正規表現が好きではなく、効率についてまったく気にしない場合は、この例を使用して 3 つの段階で同じ効果を達成しました。

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

数字を含むものを含め、上記のすべてのテスト ケースに合格します。

私が言うように、これは他の例で 1 つの正規表現を使用するほど良くはありませんが、誰かがそれを便利だと思うかもしれません。

于 2012-01-12T15:13:14.937 に答える
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

于 2010-12-18T06:13:49.643 に答える
1

次の正規表現を使用して、単語内の大文字を識別できます。

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

これは、すべての大文字、つまり大文字以外の文字または数字の後のエーテル、またはその後に小文字と文字の後のすべての数字に一致します。

それらの前にスペースを挿入する方法は、私のJavaスキルを超えています=)

数字のケースと PDF ローダーのケースを含むように編集されました。

于 2010-04-01T10:47:58.373 に答える
1

文字列を繰り返し処理し、小文字から大文字、大文字から小文字、アルファベットから数字、数字からアルファベットへの変更を検出する必要があると思います。ただし、変更を検出するたびに、1 つの例外を除いてスペースを挿入します。大文字から小文字への変更では、1 文字前にスペースを挿入します。

于 2010-04-01T11:06:05.747 に答える
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"

于 2011-07-03T06:13:16.720 に答える
0

polygenelubricants から正規表現を取得し、それをオブジェクトの拡張メソッドに変換しました。

    /// <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 によって指定された正規表現を使用して、文字列を分割します。次に、最初の単語と頭字語を除く各単語を ToLowers します。そこにいる誰かに役立つかもしれないと思った。

于 2012-08-16T15:58:12.793 に答える
-2

私は正規表現の忍者ではないので、現在の位置と前の位置のインデックスをチェックしながら、文字列を反復処理します。現在の位置が大文字の場合、前の位置の後にスペースを挿入し、各インデックスをインクリメントします。

于 2010-06-04T00:20:26.550 に答える
-3

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

String.underscore().humanize()メソッドをチェーンして、 CamelCase文字列を取得し、それを人間が読める文字列に変換できます。

于 2010-05-03T14:43:38.057 に答える