Compartilhamento de tecnologia

? em expressões regulares

2024-07-12

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

Em expressões regulares,? Pode representar uma quantidade, 0 ou 1 vezes, equivalente a {0, 1}, ou pode ser usado como caractere especial para representar outros significados.

correspondência não gananciosa

? seguido por outros qualificadores de quantidade indica uma correspondência não gananciosa, ou seja, corresponde à sequência mais curta possível que é pesquisada.

Vejamos um exemplo:

  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. }

Saída após a execução: abcabc

Não é a partida mais curta? Por que falhou?

Na verdade, isso envolve as regras da correspondência não gananciosa:Correspondência não gananciosa, o caminho mais curto é correspondido antes da próxima regra. Se não houver próxima regra, ela é processada como correspondência gananciosa.

Ou seja, se apenas "a.*?" aparecer, ele ainda será processado de acordo com a correspondência gananciosa.

Vejamos o uso correto:

  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. }

Saída após a execução:

  1. afcafc
  2. a
  3. fcafc

Como você pode ver, o primeiro grupo de captura captura a string mais curta “a” e o segundo grupo de captura captura “fcafc”.

Vejamos as outras duas situações:

  • "(a.*)(.*)" O primeiro grupo de captura capturará tudo, o segundo grupo de captura não reportará um erro, mas não capturará nada.
  • "(a.*?)(.*?)" O primeiro grupo de captura capturará "a" e o segundo grupo de captura capturará "fcafc". .

Combine, mas não capture (?:padrão)

Quando usado em um grupo de captura, ?: é colocado antes da expressão regular para indicar correspondência, mas não captura, ou seja, este grupo de valores correspondentes não pode ser obtido através do método de grupo.

Vamos ver um exemplo

  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. }

Será reportado um erro ao capturar através do grupo(1), ou seja, pode ser correspondido, mas não pode ser capturado. Se ?: for removido, group(1) poderá ser usado para capturar normalmente.

Ativar modo de linha única (?s)

(?s) ativa o modo de linha única no lado direito, fazendo com que .

Vejamos um exemplo:

  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. }

Ao capturar, (?s) não pode ser capturado como um grupo de captura, então "((?s).*)" pode capturar o grupo(1) no máximo, e um erro será relatado ao capturar o grupo(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. }

Após remover o (?s), tente corresponder "abcnsdf". Como há um caractere de nova linha, a correspondência não pode ser concluída, portanto, nada será gerado.