Java regex capturando índices de grupos

113

Eu tenho a seguinte linha,

typeName="ABC:xxxxx;";

Eu preciso buscar a palavra ABC,

Eu escrevi o seguinte trecho de código,

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

Então, se eu coloco group(0)eu recebo, ABC:mas se eu coloco group(1)é ABC, então eu quero saber

  1. O que isso 0e 1significa? Será melhor se alguém puder me explicar com bons exemplos.

  2. O padrão regex contém um :nele, então por que o group(1)resultado omite isso? O grupo 1 detecta todas as palavras entre parênteses?

  3. Então, se eu colocar mais dois parênteses como,: \\s*(\d*)(.*)então, haverá dois grupos? group(1)vai devolver a (\d*)peça e group(2)devolver a (.*)peça?

O trecho de código foi fornecido com o objetivo de limpar minhas confusões. Não é o código com o qual estou lidando. O código fornecido acima pode ser executado de String.split()uma maneira muito mais fácil.

P basak
fonte

Respostas:

182

Captura e agrupamento

Grupo de captura (pattern) cria um grupo que possui propriedade de captura .

Um relacionado que você pode ver (e usar) com frequência é o (?:pattern), que cria um grupo sem capturar propriedade, portanto, denominado grupo de não captura .

Um grupo é geralmente usado quando você precisa repetir uma sequência de padrões, por exemplo (\.\w+)+, ou para especificar onde a alternância deve ter efeito, por exemplo ^(0*1|1*0)$( ^, então 0*1ou 1*0, então $) versus ^0*1|1*0$( ^0*1ou 1*0$).

Um grupo de captura, além do agrupamento, também gravará o texto correspondente ao padrão dentro do grupo de captura (pattern). Usando o seu exemplo, (.*):, .*jogosABC e :jogos :, e uma vez que .*está dentro de grupo de captura (.*), o texto ABCé gravado para o grupo de captura 1.

Número do grupo

Todo o padrão é definido como o número do grupo 0.

Qualquer grupo de captura no padrão começa a indexação de 1. Os índices são definidos pela ordem dos parênteses de abertura dos grupos de captura . Por exemplo, aqui estão todos 5 grupos de captura no padrão abaixo:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

Os números do grupo são usados ​​na referência anterior \n no padrão e $nna string de substituição.

Em outros tipos de regex (PCRE, Perl), eles também podem ser usados ​​em chamadas de sub-rotina .

Você pode acessar o texto correspondido por determinado grupo com Matcher.group(int group) . Os números dos grupos podem ser identificados com a regra indicada acima.

Em alguns tipos de regex (PCRE, Perl), há um recurso de redefinição de ramificação que permite usar o mesmo número para capturar grupos em diferentes ramificações de alternância .

Nome do grupo

No Java 7, você pode definir um grupo de captura nomeado (?<name>pattern) e pode acessar o conteúdo correspondente Matcher.group(String name). A regex é mais longa, mas o código é mais significativo, pois indica o que você está tentando corresponder ou extrair com a regex.

Os nomes dos grupos são usados ​​na referência anterior \k<name>no padrão e ${name}na string de substituição.

Os grupos de captura nomeados ainda são numerados com o mesmo esquema de numeração, portanto, também podem ser acessados ​​via Matcher.group(int group).

Internamente, a implementação do Java mapeia apenas do nome ao número do grupo. Portanto, você não pode usar o mesmo nome para 2 grupos de captura diferentes.

nhahtdh
fonte
1
UAU! Obrigado @nhahtdh por explicar os grupos de não captura sobre como funciona a ordem do grupo de aninhamento. Eu estava perplexo sobre como os números dos grupos funcionavam até que finalmente li sua explicação. Muito obrigado!
MMeah
92

Para o resto de nós

Aqui está um exemplo simples e claro de como isso funciona

Regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

Corda: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

Como você pode ver, criei CINCO grupos, cada um entre parênteses.

Incluí! * E *! em ambos os lados para torná-lo mais claro. Observe que nenhum desses caracteres está no RegEx e, portanto, não serão produzidos nos resultados. Grupo (0) apenas fornece a string inteira correspondida (todos os meus critérios de pesquisa em uma única linha). O grupo 1 para logo antes do primeiro espaço porque o caractere de espaço não foi incluído nos critérios de pesquisa. Os grupos 2 e 4 são simplesmente o espaço em branco, que neste caso é literalmente um caractere de espaço, mas também pode ser uma guia ou uma alimentação de linha etc. O grupo 3 inclui o espaço porque eu o coloquei nos critérios de pesquisa ... etc.

Espero que isso faça sentido.

Michael Sims
fonte
1
exemplo perfeito e fácil de entender para iniciantes. Tenho uma dúvida é o mesmo que agrupamento reg ex em python? ou então há alguma diferença? eu sou novo no reg ex é por isso que estou um pouco confuso nos dois idiomas.
Mani
1
Este não é um regex Java válido: as barras invertidas devem ser duplicadas.
Nicolas Raoul
1
@NicolasRaoul: Barra invertida dupla deve-se à sintaxe de escape na literal de string. A sintaxe real do regex (ou seja, se você imprimir a string que contém o regex no console) não requer barra invertida dupla.
nhahtdh
@NicolasRaoul Se você copiasse e colasse minha string regex no código Java real usando um IDE competente, o IDE formataria adequadamente as barras de escape conforme necessário. Mas meu Regex é técnica e sintaticamente correto e serve ao propósito principal que é demonstrar a associação entre o código regex e os resultados obtidos (usando um exemplo muito específico) ... iluminar um pouco ... ☺
Michael Sims
44

Parêntese () são usados ​​para permitir o agrupamento de frases regex.

O group(1)contém a string que está entre parênteses, (.*)então.* neste caso

E group(0) contém toda a string correspondente.

Se você tivesse mais grupos (ler (...)), seria colocado em grupos com os próximos índices (2, 3 e assim por diante).

Michal Borek
fonte
2
Então, estou correto que adicionar parênteses é na verdade para criar grupos?
P basak de
3
Sim, podemos dizer isso.
Michal Borek