기술나눔

? 정규식에서

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

정규식에서는? 이는 {0, 1}에 해당하는 0 또는 1번 수량을 나타내거나 다른 의미를 나타내는 특수 문자로 사용될 수 있습니다.

탐욕스럽지 않은 일치

? 뒤에 다른 수량 한정자가 오면 탐욕스럽지 않은 일치, 즉 검색된 가능한 가장 짧은 문자열과 일치함을 나타냅니다.

예를 살펴보겠습니다:

  1. @Test
  2. public void test() {
  3. Pattern pattern = Pattern.compile("a.*?");
  4. Matcher matcher = pattern.matcher("abcabc");
  5. if (matcher.matches()) {
  6. System.out.println(matcher.group());
  7. }
  8. }

실행 후 출력: abcabc

최단시간 일치 아닌가요? 왜 실패했나요?

이는 실제로 탐욕스럽지 않은 일치 규칙을 포함합니다.비탐욕적 매칭(Non-greedy match)은 다음 규칙 이전에 최단 경로를 매칭하는 방식으로, 다음 규칙이 없을 경우 탐욕적 매칭으로 처리된다.

즉, "a.*?"만 나타나는 경우에도 그리디 매칭에 따라 처리됩니다.

올바른 사용법을 살펴보겠습니다.

  1. @Test
  2. public void test() {
  3. Pattern pattern = Pattern.compile("(a.*?)(.*)");
  4. Matcher matcher = pattern.matcher("afcafc");
  5. if (matcher.matches()) {
  6. System.out.println(matcher.group(0));
  7. System.out.println(matcher.group(1));
  8. System.out.println(matcher.group(2));
  9. }
  10. }

실행 후 출력:

  1. afcafc
  2. a
  3. fcafc

보시다시피 첫 번째 캡처링 그룹은 가장 짧은 문자열 "a"를 캡처하고 두 번째 캡처링 그룹은 "fcafc"를 캡처합니다.

다른 두 가지 상황을 살펴보겠습니다.

  • "(a.*)(.*)" 첫 번째 캡처 그룹은 모든 것을 캡처하고, 두 번째 캡처 그룹은 오류를 보고하지 않지만 아무것도 캡처하지 않습니다.
  • "(a.*?)(.*?)" 첫 번째 캡처 그룹은 "a"를 캡처하고 두 번째 캡처 그룹은 "fcafc"를 캡처합니다. 이후에는 다른 규칙이 없으므로 그리디 매칭에 따라 처리됩니다. .

일치하지만 캡처하지 않음(?:pattern)

캡처링 그룹에서 사용되는 경우 정규식 앞에 ?:가 배치되어 일치하지만 캡처되지 않음을 나타냅니다. 즉, 이 일치하는 값 그룹은 그룹 방법을 통해 얻을 수 없습니다.

예를 보자

  1. @Test
  2. public void test0() {
  3. Pattern pattern = Pattern.compile("\d{4}-(?:[a-z]+)");
  4. Matcher matcher = pattern.matcher("3214-opo");
  5. if (matcher.matches()) {
  6. System.out.println(matcher.group());
  7. System.out.println(matcher.group(1)); // 报错
  8. }
  9. }

그룹(1)을 통해 캡처할 때 오류가 보고됩니다. 즉, 일치할 수는 있지만 캡처할 수는 없습니다. ?:를 제거하면 group(1)을 사용하여 정상적으로 캡처할 수 있습니다.

단일 라인 모드 활성화(?s)

(?s)는 오른쪽의 한 줄 모드를 활성화하여 .가 개행 문자 n을 포함한 모든 문자와 일치하도록 합니다.

예를 살펴보겠습니다:

  1. private static final String DEFAULT_VARIABLE_PATTERN = "((?s).*)";
  2. /**
  3. * 从输出结果可知,匹配到了换行符 'n'
  4. */
  5. @Test
  6. public void test4() {
  7. Pattern pattern = Pattern.compile(DEFAULT_VARIABLE_PATTERN);
  8. Matcher matcher = pattern.matcher("abcnsdf");
  9. if (matcher.matches()) {
  10. System.out.println(matcher.group());
  11. System.out.println(matcher.group(1));
  12. System.out.println(matcher.group(2)); // (?s) 不能作为捕获组,报错
  13. }
  14. }

캡처 시 (?s)는 캡처 그룹으로 캡처할 수 없으므로 "((?s).*)"는 최대 그룹(1)을 캡처할 수 있으며, 그룹(2) 캡처 시 오류가 보고됩니다.

  1. @Test
  2. public void test5() {
  3. Pattern pattern = Pattern.compile("(.*)");
  4. Matcher matcher = pattern.matcher("abcnsdf");
  5. if (matcher.matches()) {
  6. System.out.println(matcher.group());
  7. System.out.println(matcher.group(1));
  8. }
  9. }

(?s)를 제거한 후 "abcnsdf"를 일치시켜 보십시오. 개행 문자가 있기 때문에 일치가 완료되지 않으므로 아무것도 출력되지 않습니다.