Обмен технологиями

? в регулярных выражениях

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

Разве это не самый короткий матч? Почему это не удалось?

На самом деле это включает в себя правила нежадного сопоставления:При нежадном сопоставлении кратчайший путь сопоставляется перед следующим правилом. Если следующего правила нет, оно обрабатывается как жадное сопоставление.

То есть, если появится только «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». Поскольку других правил позже не будет, она будет обработана в соответствии с жадным сопоставлением. .

Сопоставлять, но не захватывать (?:шаблон)

При использовании в группе захвата ?: ставится перед регулярным выражением, чтобы указать на совпадение, но не на захват, то есть эту группу совпадающих значений невозможно получить с помощью метода group.

Давайте посмотрим пример

  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) будет сообщено об ошибке, то есть ее можно сопоставить, но нельзя захватить. Если ?: удален, его можно нормально захватить через группу (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». Поскольку существует символ новой строки, сопоставление невозможно завершить, поэтому ничего не будет выведено.