brilliant RegEx を見つけて、camelCaseまたはTitleCase式の一部を抽出しました。
(?<!^)(?=[A-Z])
期待どおりに動作します:
たとえば、Javaの場合:
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
//words equals words = new String[]{"lorem","Ipsum"}
私の問題は、場合によっては機能しないことです:
私の考えでは、結果は次のようになります。
つまり、n個の大文字が与えられた場合:
この正規表現を改善する方法についてのアイデアはありますか?
次の正規表現は、上記のすべての例で機能します。
public static void main(String[] args)
{
for (String w : "camelValue".split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")) {
System.out.println(w);
}
}
文字列の先頭で一致を無視するだけでなく、大文字の前に別の大文字が含まれる一致を無視するように、負の後ろ読みを強制することで機能します。これにより、「VALUE」などのケースが処理されます。
正規表現の最初の部分は、「eclipseRCPExt」で「RPC」と「Ext」に分割できないため、失敗します。これが2番目の句の目的です:(?<!^)(?=[A-Z][a-z]
。この句により、文字列の先頭を除いて、小文字が続くすべての大文字の前で分割できます。
これを必要以上に複雑にしているようです。 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
編集:20130824RCPExt -> RCP / Ext
ケース。
別の解決策は、 commons-lang で専用メソッドを使用することです。 StringUtils#splitByCharacterTypeCamelCase
私は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)
ここでは、各Wordをスペースで区切ります。そのため、文字列の変換方法の例をいくつか示します。
上記のこのソリューションは元の投稿が求めることを行いますが、数字を含むラクダとPascalの文字列を見つけるための正規表現も必要だったので、数字を含めるためにこのバリエーションを思い付きました:
((^[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)
そして、この正規表現を使用して数字を含む文字列を変換する方法の例を次に示します。
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"));
}
}
ここでの両方の上位の回答は、すべての正規表現フレーバーでサポートされているわけではない、ポジティブルックビハインドを使用したコードを提供します。以下の正規表現は、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
[A-Z]+
に一致[A-Z]?
に一致し、その後に1個以上の小文字のアルファベット文字[a-z]+
が続く[A-Z]
またはワード境界文字\b
であることを確認してください次の式をJavaに使用できます。
(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?=[A-Z][a-z])|(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)
正規表現文字列([A-Z]+|[A-Z]?[a-z]+)(?=[A-Z]|\b)
上記のctwheelsによって与えられたものは、マイクロソフトの正規表現と連動します。
また、ctwheelsの正規表現に基づいて、数字を処理する次の代替案を提案したいと思います:([A-Z0-9]+|[A-Z]?[a-z]+)(?=[A-Z0-9]|\b)
。
これにより、次のような文字列を分割できます。
運転B2BTradeIn2019以降
に
2019年以降のB2Bトレードの推進
存在しないの区切り文字を探す代わりに、名前コンポーネントの検索を検討することもできます(確かに存在します)。
String test = "_Eclipse福福RCPExt";
Pattern componentPattern = Pattern.compile("_? (\\p{Upper}?\\p{Lower}+ | (?:\\p{Upper}(?!\\p{Lower}))+ \\p{Digit}*)", Pattern.COMMENTS);
Matcher componentMatcher = componentPattern.matcher(test);
List<String> components = new LinkedList<>();
int endOfLastMatch = 0;
while (componentMatcher.find()) {
// matches should be consecutive
if (componentMatcher.start() != endOfLastMatch) {
// do something horrible if you don't want garbage in between
// we're lenient though, any Chinese characters are lucky and get through as group
String startOrInBetween = test.substring(endOfLastMatch, componentMatcher.start());
components.add(startOrInBetween);
}
components.add(componentMatcher.group(1));
endOfLastMatch = componentMatcher.end();
}
if (endOfLastMatch != test.length()) {
String end = test.substring(endOfLastMatch, componentMatcher.start());
components.add(end);
}
System.out.println(components);
これは[Eclipse, 福福, RCP, Ext]
を出力します。配列への変換はもちろん簡単です。