88

camelCase または TitleCase 式の一部を抽出する素晴らしい RegExを見つけました。

 (?<!^)(?=[A-Z])

期待どおりに動作します:

  • 値 -> 値
  • camelValue -> キャメル / 値
  • TitleValue -> タイトル / 値

Java の例:

String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
//words equals words = new String[]{"lorem","Ipsum"}

私の問題は、場合によっては機能しないことです。

  • ケース 1: 値 -> V / A / L / U / E
  • ケース 2: eclipseRCPExt -> eclipse / R / C / P / Ext

私の考えでは、結果は次のようになります。

  • ケース 1: 値
  • ケース 2: Eclipse / RCP / Ext

つまり、n 個の大文字が与えられた場合:

  • n 文字の後に小文字が続く場合、グループは次のようになります: (n-1 文字) / (n 番目の文字 + 小文字)
  • n 文字が最後にある場合、グループは次のようになります: (n 文字)。

この正規表現を改善する方法について何か考えはありますか?

4

11 に答える 11

117

次の正規表現は、上記のすべての例で機能します。

public static void main(String[] args)
{
    for (String w : "camelValue".split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")) {
        System.out.println(w);
    }
}   

これは、文字列の先頭の一致を無視するだけでなく、大文字の前に別の大文字がある場所の一致も無視するように、否定後読みを強制することによって機能します。これは、「VALUE」のようなケースを処理します。

正規表現の最初の部分は、「RPC」と「Ext」の間の分割に失敗することにより、「eclipseRCPExt」で失敗します。これが 2 番目の句の目的です(?<!^)(?=[A-Z][a-z]。この句は、文字列の先頭を除き、小文字が続くすべての大文字の前で分割を許可します。

于 2011-09-29T07:45:57.340 に答える
86

これを必要以上に複雑にしているようです。camelCaseの場合、分割位置は単純に小文字の直後に大文字が続く場所です。

(?<=[a-z])(?=[A-Z])

この正規表現がサンプル データを分割する方法は次のとおりです。

  • value -> value
  • camelValue -> camel / Value
  • TitleValue -> Title / Value
  • VALUE -> VALUE
  • eclipseRCPExt -> eclipse / RCPExt

目的の出力との唯一の違いは、eclipseRCPExtここでは正しく分割されていると私は主張します。

補遺 - 改良版

注:この回答は最近賛成票を獲得し、より良い方法があることに気付きました...

上記の正規表現に 2 番目の代替を追加することで、OP のすべてのテスト ケースが正しく分割されます。

(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])

改善された正規表現がサンプル データをどのように分割するかを次に示します。

  • value -> value
  • camelValue -> camel / Value
  • TitleValue -> Title / Value
  • VALUE -> VALUE
  • eclipseRCPExt -> eclipse / RCP / Ext

編集:20130824ケースを処理するための改良版を追加しましたRCPExt -> RCP / Ext

于 2011-09-29T15:27:26.147 に答える
32

別の解決策は、 commons-langで専用のメソッドを使用することです: StringUtils#splitByCharacterTypeCamelCase

于 2011-09-29T18:56:27.833 に答える
10

私はaixのソリューションを機能させることができませんでした(RegExrでも機能しません)ので、私がテストした独自のものを思いつき、あなたが探していることを正確に行うようです:

((^[a-z]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($))))

これを使用する例を次に示します。

; Regex Breakdown:  This will match against each word in Camel and Pascal case strings, while properly handling acrynoms.
;   (^[a-z]+)                       Match against any lower-case letters at the start of the string.
;   ([A-Z]{1}[a-z]+)                Match against Title case words (one upper case followed by lower case letters).
;   ([A-Z]+(?=([A-Z][a-z])|($)))    Match against multiple consecutive upper-case letters, leaving the last upper case letter out the match if it is followed by lower case letters, and including it if it's followed by the end of the string.
newString := RegExReplace(oldCamelOrPascalString, "((^[a-z]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($))))", "$1 ")
newString := Trim(newString)

ここでは、各単語をスペースで区切ります。文字列がどのように変換されるかの例を次に示します。

  • ThisIsATitleCASEString => これはタイトル CASE 文字列です
  • andThisOneIsCamelCASE => and This One Is Camel CASE

上記のこのソリューションは、元の投稿が求めていることを実行しますが、数字を含むキャメル文字列とパスカル文字列を見つけるために正規表現も必要だったので、数字を含めるためにこのバリエーションも思いつきました:

((^[a-z]+)|([0-9]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($)|([0-9]))))

そしてそれを使用する例:

; Regex Breakdown:  This will match against each word in Camel and Pascal case strings, while properly handling acrynoms and including numbers.
;   (^[a-z]+)                               Match against any lower-case letters at the start of the command.
;   ([0-9]+)                                Match against one or more consecutive numbers (anywhere in the string, including at the start).
;   ([A-Z]{1}[a-z]+)                        Match against Title case words (one upper case followed by lower case letters).
;   ([A-Z]+(?=([A-Z][a-z])|($)|([0-9])))    Match against multiple consecutive upper-case letters, leaving the last upper case letter out the match if it is followed by lower case letters, and including it if it's followed by the end of the string or a number.
newString := RegExReplace(oldCamelOrPascalString, "((^[a-z]+)|([0-9]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($)|([0-9]))))", "$1 ")
newString := Trim(newString)

数値を含む文字列がこの正規表現で変換される方法の例を次に示します。

  • myVariable123 => 私の変数 123
  • my2Variables => 私の 2 つの変数
  • The3rdVariableIsHere => 3 番目の変数はここにあります
  • 12345NumsAtTheStartIncludedToo => 12345 開始時の数値も含まれる
于 2012-03-11T06:40:53.697 に答える
4

だけでなく、より多くの文字を処理するにはA-Z:

s.split("(?<=\\p{Ll})(?=\\p{Lu})|(?<=\\p{L})(?=\\p{Lu}\\p{Ll})");

また:

  • 小文字の後に分割し、その後に大文字を続けます。

parseXML-> parse, XML.

また

  • 任意の文字の後に分割し、その後に大文字と小文字が続きます。

XMLParser-> XML, Parser.


より読みやすい形式で:

public class SplitCamelCaseTest {

    static String BETWEEN_LOWER_AND_UPPER = "(?<=\\p{Ll})(?=\\p{Lu})";
    static String BEFORE_UPPER_AND_LOWER = "(?<=\\p{L})(?=\\p{Lu}\\p{Ll})";

    static Pattern SPLIT_CAMEL_CASE = Pattern.compile(
        BETWEEN_LOWER_AND_UPPER +"|"+ BEFORE_UPPER_AND_LOWER
    );

    public static String splitCamelCase(String s) {
        return SPLIT_CAMEL_CASE.splitAsStream(s)
                        .collect(joining(" "));
    }

    @Test
    public void testSplitCamelCase() {
        assertEquals("Camel Case", splitCamelCase("CamelCase"));
        assertEquals("lorem Ipsum", splitCamelCase("loremIpsum"));
        assertEquals("XML Parser", splitCamelCase("XMLParser"));
        assertEquals("eclipse RCP Ext", splitCamelCase("eclipseRCPExt"));
        assertEquals("VALUE", splitCamelCase("VALUE"));
    }    
}
于 2013-02-11T16:09:56.027 に答える
4

簡単に

ここでの両方の上位の回答は、すべての正規表現フレーバーでサポートされていない、肯定的な後読みを使用するコードを提供します。PascalCase以下の正規表現は、 と の両方をキャプチャcamelCaseし、複数の言語で使用できます。

注:この質問が Java に関するものであることは認識していますが、この投稿について、さまざまな言語でタグ付けされた他の質問で複数の言及があり、この質問に対するコメントも同じです。

コード

ここで使用されているこの正規表現を参照してください

([A-Z]+|[A-Z]?[a-z]+)(?=[A-Z]|\b)

結果

サンプル入力

eclipseRCPExt

SomethingIsWrittenHere

TEXTIsWrittenHERE

VALUE

loremIpsum

サンプル出力

eclipse
RCP
Ext

Something
Is
Written
Here

TEXT
Is
Written
HERE

VALUE

lorem
Ipsum

説明

  • 1 つ以上の大文字の英字に一致[A-Z]+
  • または、 0 個または 1 個の大文字の英字に一致[A-Z]?し、その後に 1 つ以上の小文字の英字が続きます。[a-z]+
  • 後続が大文字の英字[A-Z]または単語境界文字であることを確認してください\b
于 2017-09-25T15:54:43.393 に答える
0

Java では、次の式を使用できます。

(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?=[A-Z][a-z])|(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)
于 2016-07-10T23:31:25.343 に答える