[java] 작은 따옴표 나 큰 따옴표로 묶지 않을 때 공백을 사용하여 문자열을 분할하는 정규식

정규식을 처음 사용하며 도움을 주시면 감사하겠습니다. 작은 따옴표 나 큰 따옴표로 묶지 않은 모든 공백을 사용하여 예제 문자열을 분할하는 표현식을 작성하려고합니다. 내 마지막 시도는 다음과 같습니다. (?!")그리고 제대로 작동하지 않습니다. 따옴표 앞의 공간에서 분할됩니다.

입력 예 :

This is a string that "will be" highlighted when your 'regular expression' matches something.

원하는 출력 :

This
is
a
string
that
will be
highlighted
when
your
regular expression
matches
something.

참고 "will be"'regular expression'단어 사이의 간격을 유지한다.



답변

나는 다른 모든 사람들이 왜 그렇게 복잡한 정규식이나 그렇게 긴 코드를 제안하는지 이해하지 못합니다. 기본적으로 문자열에서 두 가지 종류의 항목을 가져 오려고합니다. 즉, 공백이나 따옴표가 아닌 문자 시퀀스와 두 종류의 따옴표에 대해 따옴표로 시작하고 끝나는 문자 시퀀스 (사이에 따옴표없이)가 있습니다. 다음 정규식을 사용하여 이러한 항목을 쉽게 일치시킬 수 있습니다.

[^\s"']+|"([^"]*)"|'([^']*)'

목록에서 따옴표를 원하지 않기 때문에 캡처 그룹을 추가했습니다.

이 Java 코드는 목록을 작성하고 일치하는 경우 캡처 그룹을 추가하여 따옴표를 제외하고 캡처하는 그룹이 일치하지 않으면 전체 정규식 일치를 추가합니다 (인용되지 않은 단어가 일치 함).

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    if (regexMatcher.group(1) != null) {
        // Add double-quoted string without the quotes
        matchList.add(regexMatcher.group(1));
    } else if (regexMatcher.group(2) != null) {
        // Add single-quoted string without the quotes
        matchList.add(regexMatcher.group(2));
    } else {
        // Add unquoted word
        matchList.add(regexMatcher.group());
    }
} 

반환 된 목록에 따옴표가 있어도 괜찮다면 훨씬 더 간단한 코드를 사용할 수 있습니다.

List<String> matchList = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"[^\"]*\"|'[^']*'");
Matcher regexMatcher = regex.matcher(subjectString);
while (regexMatcher.find()) {
    matchList.add(regexMatcher.group());
} 


답변

정규식을 사용하여 다양한 컨텍스트에서 동일한 질문을 다루는 StackOverflow에 대한 몇 가지 질문이 있습니다. 예를 들면 :

UPDATE : 작은 따옴표와 큰 따옴표로 묶인 문자열을 처리하기위한 샘플 정규식입니다. 참고 : 따옴표 안에있을 때를 제외하고 어떻게 문자열을 분할 할 수 있습니까?

m/('.*?'|".*?"|\S+)/g 

빠른 Perl 스 니펫으로 이것을 테스트했으며 출력은 아래와 같이 재현되었습니다. 또한 따옴표 사이에있는 경우 빈 문자열 또는 공백 전용 문자열에 대해 작동합니다 (원하는지 여부는 확실하지 않음).

This
is
a
string
that
"will be"
highlighted
when
your
'regular expression'
matches
something.

여기에는 일치하는 값에 따옴표 문자 자체가 포함되지만 문자열 바꾸기로 제거하거나 정규식을 수정하여 포함하지 않을 수 있습니다. 나는 2am이 더 이상 정규 표현식을 엉망으로 만들기에는 너무 늦기 때문에 독자 또는 다른 포스터를위한 연습으로 남겨 둘 것입니다.)


답변

문자열 안에 이스케이프 된 따옴표를 허용하려면 다음과 같이 사용할 수 있습니다.

(?:(['"])(.*?)(?<!\\)(?>\\\\)*\1|([^\s]+))

인용 된 문자열은 그룹 2, 인용되지 않은 단일 단어는 그룹 3이됩니다.

http://www.fileformat.info/tool/regex.htm 또는 http://gskinner.com/RegExr/ 에서 다양한 문자열로 시도 할 수 있습니다.


답변

Jan Goyvaerts의 정규식은 지금까지 찾은 최고의 솔루션이지만 빈 (null) 일치 항목도 생성하여 프로그램에서 제외합니다. 이러한 빈 일치는 정규식 테스터 (예 : rubular.com)에서도 나타납니다. 검색 배열을 바꾸면 (먼저 인용 된 부분과 공백으로 구분 된 단어보다 검색) 다음을 사용하여 한 번에 수행 할 수 있습니다.

("[^"]*"|'[^']*'|[\S]+)+


답변

(?<!\G".{0,99999})\s|(?<=\G".{0,99999}")\s

이것은 큰 따옴표로 묶지 않은 공백과 일치합니다. Java는 lookbehind에서 * 및 +를 지원하지 않기 때문에 min, max {0,99999}를 사용해야합니다.


답변

문자열을 검색하고 각 부분을 잡아서 분할하는 것이 더 쉬울 것입니다.

이유는 이전과 이후의 공간에서 분할 할 수 있기 때문 "will be"입니다. 그러나 분할 내부 사이의 공간을 무시하는 것을 지정하는 방법을 생각할 수 없습니다.

(실제 Java가 아님)

string = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";

regex = "\"(\\\"|(?!\\\").)+\"|[^ ]+"; // search for a quoted or non-spaced group
final = new Array();

while (string.length > 0) {
    string = string.trim();
    if (Regex(regex).test(string)) {
        final.push(Regex(regex).match(string)[0]);
        string = string.replace(regex, ""); // progress to next "word"
    }
}

또한 작은 따옴표를 캡처하면 다음과 같은 문제가 발생할 수 있습니다.

"Foo's Bar 'n Grill"

//=>

"Foo"
"s Bar "
"n"
"Grill"


답변

String.split()따옴표 안의 공백 (분할하지 않음)과 바깥 쪽 (분할)을 구분할 방법이 없기 때문에 여기서는 도움이되지 않습니다. Matcher.lookingAt()아마도 필요한 것입니다.

String str = "This is a string that \"will be\" highlighted when your 'regular expression' matches something.";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|('[^']+?')|([^\\s]+?))\\s++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")) ||
            (s.startsWith("'") && s.endsWith("'")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

다음 출력을 생성합니다.

0: "This"
5: "is"
8: "a"
10: "string"
17: "that"
22: "will be"
32: "highlighted"
44: "when"
49: "your"
54: "regular expression"
75: "matches"
83: "something."