Não. Duas ocorrências de Xé o melhor que você pode obter para o geral m, n.
John Dvorak
Se esse fosse meu problema, eu tentaria backreferences regex e começaria com (X)\1{n-1}(?:\1{m-n-1}). Eu sei que isso corresponde Xpelo menos uma vez, mas apenas para começar, tente essa coisa simples e, em seguida, refine usando lookaheads ou lookbehinds em vez de (X).
basicamente
Respostas:
91
Não existe um quantificador único que significa "exatamente m ou n vezes". A maneira como você está fazendo isso é ótima.
Por que o é ?:necessário no m = 2nexemplo if ? Parece funcionar bem sem ele para mim.
erb
7
@erb se você o deixar de fora ?:, o grupo se torna um grupo de captura. Além do mecanismo de regex lembrar coisas que não precisa, se você tiver grupos de captura após esse, seus IDs serão alterados. Se você usar sua regex para substituição, terá que ajustar a substituição.
John Dvorak
19
Não, não existe tal quantificador. Mas eu o reestruturaria /X{m}(X{m-n})?/para evitar problemas de retrocesso .
Parece que você quer "xn times" ou "xm times", acho que uma tradução literal para regex seria (x{n}|x{m}).
assim https://regex101.com/r/vH7yL5/1
ou, em um caso onde você pode ter uma sequência de mais de m "x" s (assumindo m> n), você pode adicionar 'não seguindo "x"' e 'seguido por nenhum "x", traduzindo para [^x](x{n}|x{m})[^x]mas isso seria suponha que sempre há um caractere atrás e depois de "x" s. Como você pode ver aqui: https://regex101.com/r/bB2vH2/1
você pode alterá-lo para (?:[^x]|^)(x{n}|x{m})(?:[^x]|$), traduzindo para "não seguindo 'x' ou seguindo o início da linha" e "seguido por nenhum 'x' ou seguido pelo fim da linha". Mas, ainda assim, não combinará duas sequências com apenas um caractere entre elas (porque a primeira correspondência exigiria um caractere depois, e a segunda um caractere antes) como você pode ver aqui: https://regex101.com/r/ oC5oJ4 / 1
Finalmente, para combinar a correspondência distante de um caractere, você pode adicionar um olhar positivo para frente (? =) No "não 'x' depois" ou um olhar positivo para trás (? <=) No "não 'x' antes", assim: https://regex101.com/r/mC4uX3/1
(?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)
Dessa forma, você corresponderá apenas ao número exato de 'x's que deseja.
Observando a resposta de Enhardened, eles afirmam que sua penúltima expressão não corresponderá a sequências com apenas um caractere entre elas. Há uma maneira fácil de consertar isso sem usar look ahead / look behind, que é substituir o caractere de início / fim pelo caractere de limite. Isso permite que você compare os limites das palavras, incluindo início / fim. Como tal, a expressão apropriada deve ser:
Legal, eu não estava familiarizado com a forma como o regex lida com os limites. O único problema com este método é quando você está usando um limite não padrão. Conte uma olhada: regex101.com/r/j0nkeo/1 e regex101.com/r/4Ix7Dr/1
Enhardened em
1
@Enhardened - esse é um bom ponto, parece ser um problema com vários grupos de correspondência que se sobrepõem. Essa é uma situação em que você precisa olhar para trás.
rozza2058
1
Postagem muito antiga, mas gostaria de contribuir com algo que pode ajudar. Eu tentei exatamente da maneira indicada na pergunta e funciona, mas há um problema: a ordem das quantidades é importante. Considere isto:
#[a-f0-9]{6}|#[a-f0-9]{3}
Isso encontrará todas as ocorrências de códigos de cores hexadecimais (eles têm 3 ou 6 dígitos). Mas quando eu viro assim
#[a-f0-9]{3}|#[a-f0-9]{6}
ele encontrará apenas os de 3 dígitos ou os primeiros 3 dígitos dos de 6 dígitos. Isso faz sentido e um profissional da Regex pode perceber isso imediatamente, mas para muitos isso pode ser um comportamento peculiar. Existem alguns recursos avançados do Regex que podem evitar essa armadilha, independentemente da ordem, mas nem todo mundo está profundamente envolvido com os padrões do Regex.
X
é o melhor que você pode obter para o geralm
,n
.(X)\1{n-1}(?:\1{m-n-1})
. Eu sei que isso correspondeX
pelo menos uma vez, mas apenas para começar, tente essa coisa simples e, em seguida, refine usando lookaheads ou lookbehinds em vez de(X)
.Respostas:
Não existe um quantificador único que significa "exatamente m ou n vezes". A maneira como você está fazendo isso é ótima.
Uma alternativa é:
onde
m < n
ek
é o valor den-m
.fonte
Aqui está a lista completa de quantificadores (ref. Http://www.regular-expressions.info/reference.html ):
?
,??
- 0 ou 1 ocorrências (??
é preguiçoso,?
é ganancioso)*
,*?
- qualquer número de ocorrências+
,+?
- pelo menos uma ocorrência{n}
- exatamenten
ocorrências{n,m}
-n
param
ocorrências, inclusive{n,m}?
-n
param
ocorrências, preguiçoso{n,}
,{n,}?
- pelo menosn
ocorrênciaPara obter "exatamente N ou M", você precisa escrever o regex quantificado duas vezes, a menos que m, n sejam especiais:
X{n,m}
E sem = n+1
(?:X{n}){1,2}
E sem = 2n
fonte
?:
necessário nom = 2n
exemplo if ? Parece funcionar bem sem ele para mim.?:
, o grupo se torna um grupo de captura. Além do mecanismo de regex lembrar coisas que não precisa, se você tiver grupos de captura após esse, seus IDs serão alterados. Se você usar sua regex para substituição, terá que ajustar a substituição.Não, não existe tal quantificador. Mas eu o reestruturaria
/X{m}(X{m-n})?/
para evitar problemas de retrocesso .fonte
TLDR;
(?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)
Parece que você quer "xn times" ou "xm times", acho que uma tradução literal para regex seria
(x{n}|x{m}).
assim https://regex101.com/r/vH7yL5/1ou, em um caso onde você pode ter uma sequência de mais de m "x" s (assumindo m> n), você pode adicionar 'não seguindo "x"' e 'seguido por nenhum "x", traduzindo para
[^x](x{n}|x{m})[^x]
mas isso seria suponha que sempre há um caractere atrás e depois de "x" s. Como você pode ver aqui: https://regex101.com/r/bB2vH2/1você pode alterá-lo para
(?:[^x]|^)(x{n}|x{m})(?:[^x]|$)
, traduzindo para "não seguindo 'x' ou seguindo o início da linha" e "seguido por nenhum 'x' ou seguido pelo fim da linha". Mas, ainda assim, não combinará duas sequências com apenas um caractere entre elas (porque a primeira correspondência exigiria um caractere depois, e a segunda um caractere antes) como você pode ver aqui: https://regex101.com/r/ oC5oJ4 / 1Finalmente, para combinar a correspondência distante de um caractere, você pode adicionar um olhar positivo para frente (? =) No "não 'x' depois" ou um olhar positivo para trás (? <=) No "não 'x' antes", assim: https://regex101.com/r/mC4uX3/1
Dessa forma, você corresponderá apenas ao número exato de 'x's que deseja.
fonte
Observando a resposta de Enhardened, eles afirmam que sua penúltima expressão não corresponderá a sequências com apenas um caractere entre elas. Há uma maneira fácil de consertar isso sem usar look ahead / look behind, que é substituir o caractere de início / fim pelo caractere de limite. Isso permite que você compare os limites das palavras, incluindo início / fim. Como tal, a expressão apropriada deve ser:
(?:[^x]|\b)(x{n}|x{m})(?:[^x]|\b)
Como você pode ver aqui: https://regex101.com/r/oC5oJ4/2 .
fonte
Postagem muito antiga, mas gostaria de contribuir com algo que pode ajudar. Eu tentei exatamente da maneira indicada na pergunta e funciona, mas há um problema: a ordem das quantidades é importante. Considere isto:
Isso encontrará todas as ocorrências de códigos de cores hexadecimais (eles têm 3 ou 6 dígitos). Mas quando eu viro assim
ele encontrará apenas os de 3 dígitos ou os primeiros 3 dígitos dos de 6 dígitos. Isso faz sentido e um profissional da Regex pode perceber isso imediatamente, mas para muitos isso pode ser um comportamento peculiar. Existem alguns recursos avançados do Regex que podem evitar essa armadilha, independentemente da ordem, mas nem todo mundo está profundamente envolvido com os padrões do Regex.
fonte