camelCase 또는 TitleCase를 분할하는 RegEx (고급)
camelCase 또는 TitleCase 표현의 일부를 추출 하는 훌륭한 RegEx 를 찾았습니다 .
(?<!^)(?=[A-Z])
예상대로 작동합니다.
- 가치-> 가치
- camelValue-> 낙타 / 값
- TitleValue-> 제목 / 값
예를 들어 Java의 경우 :
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
//words equals words = new String[]{"lorem","Ipsum"}
내 문제는 어떤 경우에는 작동하지 않는다는 것입니다.
- 사례 1 : VALUE-> V / A / L / U / E
- 사례 2 : eclipseRCPExt-> eclipse / R / C / P / Ext
내 생각에 결과는 다음과 같다.
- 사례 1 : VALUE
- 사례 2 : eclipse / RCP / Ext
즉, n 개의 대문자가 주어지면 :
- n 문자 다음에 소문자가 오면 그룹은 다음과 같아야합니다. (n-1 문자) / (n 번째 문자 + 낮은 문자)
- n 개의 문자가 끝에 있으면 그룹은 (n 개의 문자) 여야합니다.
이 정규식을 개선하는 방법에 대한 아이디어가 있습니까?
다음 정규식은 위의 모든 예에서 작동합니다.
public static void main(String[] args)
{
for (String w : "camelValue".split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")) {
System.out.println(w);
}
}
네거티브 lookbehind가 문자열 시작 부분의 일치 항목을 무시할뿐만 아니라 대문자 앞에 다른 대문자가있는 일치 항목도 무시하도록 강제하여 작동합니다. "VALUE"와 같은 경우를 처리합니다.
정규식의 첫 번째 부분은 "RPC"와 "Ext"사이를 분할하지 못하여 "eclipseRCPExt"에서 실패합니다. 이것이 두 번째 절의 목적입니다 : (?<!^)(?=[A-Z][a-z]
. 이 절은 문자열의 시작 부분을 제외하고 소문자가 뒤 따르는 모든 대문자 앞에서 분할을 허용합니다.
필요한 것보다 더 복잡하게 만드는 것 같습니다. 들어 낙타 표기법 , 분할 위치는 단순히 어디 대문자 즉시 소문자 문자를 다음입니다 :
(?<=[a-z])(?=[A-Z])
이 정규식이 예제 데이터를 분할하는 방법은 다음과 같습니다.
value -> value
camelValue -> camel / Value
TitleValue -> Title / Value
VALUE -> VALUE
eclipseRCPExt -> eclipse / RCPExt
원하는 출력과의 유일한 차이점은 eclipseRCPExt
여기에서 올바르게 분할되었다고 주장하는입니다.
부록-개선 된 버전
참고 :이 답변은 최근에 찬성 투표를 받았으며 더 나은 방법이 있다는 것을 깨달았습니다.
위의 정규식에 두 번째 대안을 추가하면 모든 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)
여기에서는 각 단어를 공백으로 구분하므로 문자열이 어떻게 변형되는지에 대한 몇 가지 예가 있습니다.
- ThisIsATitleCASEString => 이것은 제목 CASE 문자열입니다
- andThisOneIsCamelCASE => 그리고 이것은 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 => 세 번째 rdVariable이 여기에 있습니다.
- 12345NumsAtTheStartIncludedToo => 시작시 12345 숫자도 포함됨
단순한 것보다 더 많은 문자를 처리하려면 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]+
- Or match zero or one uppercase alpha character
[A-Z]?
, followed by one or more lowercase alpha characters[a-z]+
- Ensure what follows is an uppercase alpha character
[A-Z]
or word boundary character\b
You can use the expression below for Java:
(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?=[A-Z][a-z])|(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)
Instead of looking for separators that aren't there you might also considering finding the name components (those are certainly there):
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);
This outputs [eclipse, 福福, RCP, Ext]
. Conversion to an array is of course simple.
I can confirm that the regex string ([A-Z]+|[A-Z]?[a-z]+)(?=[A-Z]|\b)
given by ctwheels, above, works with the Microsoft flavour of regex.
I would also like to suggest the following alternative, based on ctwheels' regex, which handles numeric characters: ([A-Z0-9]+|[A-Z]?[a-z]+)(?=[A-Z0-9]|\b)
.
This able to split strings such as:
DrivingB2BTradeIn2019Onwards
to
Driving B2B Trade in 2019 Onwards
참고URL : https://stackoverflow.com/questions/7593969/regex-to-split-camelcase-or-titlecase-advanced
'Programing' 카테고리의 다른 글
Android 머티리얼 디자인 버튼-사전 롤리팝 (0) | 2020.10.18 |
---|---|
jQuery에서 양식 변경을 어떻게 처리합니까? (0) | 2020.10.18 |
프로토콜이 특정 클래스에서만 채택되도록 요구하는 방법 (0) | 2020.10.18 |
ruby .split ( '\ n') 새 줄에서 분할되지 않음 (0) | 2020.10.18 |
iPad에서 UITableView backgroundColor 항상 흰색 (0) | 2020.10.18 |