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"));
}
これはテストケースで動作します:
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
を使用してそれらを組み合わせて読みやすくします。
3つのパターンは次のとおりです。
XMLParser AString PDFLoader
/\ /\ /\
MyClass 99Bottles
/\ /\
GL11 May5 BFG9000
/\ /\ /\
ゼロ長マッチングのルックアラウンドを使用して分割する:
org.Apache.commons.lang.StringUtils
を使用して実行できます
StringUtils.join(
StringUtils.splitByCharacterTypeCamelCase("ExampleTest"),
' '
);
きちんとした短いソリューション:
StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase("yourCamelCaseText"), StringUtils.SPACE)); // Your Camel Case Text
「複雑な」正規表現が気に入らず、効率がまったく気にならない場合は、この例を使用して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つの正規表現を使用するほど良くはありません-しかし誰かがそれを役に立つと思うかもしれません。
org.modeshape.common.text.Inflector を使用できます。
具体的には:
String humanize(String lowerCaseAndUnderscoredWords, String... removableTokens)
最初のWordを大文字にし、アンダースコアをスペースに変換し、末尾の「_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
次の正規表現を使用して、単語内の大文字を識別できます。
"((?<=[a-z0-9])[A-Z]|(?<=[a-zA-Z])[0-9]]|(?<=[A-Z])[A-Z](?=[a-z]))"
これは、すべての大文字、つまり大文字以外の文字または数字の後のエーテル、または小文字と文字の後のすべての数字の後に一致します。
それらの前にスペースを挿入する方法は私のJavaスキル=)を超えています
数字のケースとPDFローダーのケース。
文字列を反復処理し、小文字から大文字へ、大文字から小文字へ、アルファベットから数字へ、数字からアルファベットへの変更を検出する必要があると思います。ただし、変更が行われるたびにスペースが挿入されますが、1つの例外があります。大文字から小文字への変更では、1文字前にスペースが挿入されます。
これは.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;
}
ポリジェネリック潤滑剤から正規表現を取得し、オブジェクトの拡張メソッドに変換しました。
/// <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します。それはそこにいる誰かにとって役に立つかもしれないと思った。
レコードについては、ほぼ(*)互換の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"
。