Como combinar "qualquer coisa até essa sequência de caracteres" em uma expressão regular?

515

Tome esta expressão regular: /^[^abc]/. Isso corresponderá a qualquer caractere único no início de uma sequência, exceto a, b ou c.

Se você adicionar um *depois dele - /^[^abc]*/- a expressão regular continuará adicionando cada caractere subseqüente ao resultado, até encontrar um a, ou b , ou c .

Por exemplo, com a cadeia de origem "qwerty qwerty whatever abc hello", a expressão corresponderá a "qwerty qwerty wh".

Mas e se eu quisesse que a string correspondente fosse "qwerty qwerty whatever "

... Em outras palavras, como posso combinar tudo até (mas não incluindo) a sequência exata "abc" ?

callum
fonte
Como assim match but not including?
Toto
5
Quero dizer, quero combinar "qwerty qwerty whatever "- sem incluir o "abc". Em outras palavras, não quero que a correspondência resultante seja "qwerty qwerty whatever abc".
Callum
2
Em javascript, você pode apenas do string.split('abc')[0]. Certamente não é uma resposta oficial para esse problema, mas acho mais direto que o regex.
Wylliam Judd 23/05/19

Respostas:

1022

Você não especificou qual sabor de regex está usando, mas isso funcionará em qualquer um dos mais populares que podem ser considerados "completos".

/.+?(?=abc)/

Como funciona

A .+? parte é a versão não gulosa de .+ (uma ou mais de qualquer coisa). Quando usamos .+, o mecanismo basicamente corresponde a tudo. Então, se houver algo mais no regex, ele voltará em etapas tentando corresponder à parte a seguir. Esse é o comportamento ganancioso , que significa o máximo possível de satisfação .

Ao usar .+?, em vez de corresponder tudo de uma vez e voltar para outras condições (se houver), o mecanismo corresponderá aos próximos caracteres passo a passo até que a parte subsequente da regex seja correspondida (novamente, se houver). Este é o não-ganancioso , ou seja, corresponder ao mínimo possível de satisfação .

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

Depois disso, temos uma asserção de largura zero , uma olhada em volta . Essa construção agrupada corresponde ao seu conteúdo, mas não conta como caracteres correspondentes ( largura zero ). Ele retorna apenas se for uma correspondência ou não ( asserção ).(?={contents})

Assim, em outros termos, o regex /.+?(?=abc)/significa:

Combine os caracteres o menos possível até que um "abc" seja encontrado, sem contar o "abc".

sidyll
fonte
12
Provavelmente, isso não funcionará com quebras de linha, se elas forem capturadas.
einord
3
Qual é a diferença entre .+?e .*?
quer
4
@ robbie0630 +significa 1 ou mais, onde *significa 0 ou mais. A inclusão / exclusão do ?irá torná-lo ganancioso ou não ganancioso.
precisa saber é o seguinte
2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby
4
Percebi que isso falha ao selecionar qualquer coisa se o padrão que você procura não existe; em vez disso, se você usar, ^(?:(?!abc)(?!def).)*pode encadear para excluir padrões que não deseja e ainda assim agarra tudo conforme necessário, mesmo que o padrão não exista
Karan Shishoo
122

Se você deseja capturar tudo até "abc":

/^(.*?)abc/

Explicação:

( )capturar a expressão dentro dos parênteses para o acesso usando $1, $2etc.

^ coincidir com o início da linha

.*corresponde a qualquer coisa, ?sem avidez (corresponde ao número mínimo de caracteres necessário) - [1]

[1] A razão pela qual isso é necessário é que, caso contrário, na seguinte string:

whatever whatever something abc something abc

por padrão, as expressões regulares são gananciosas , o que significa que corresponderá o máximo possível. Portanto /^.*abc/corresponderia "qualquer coisa que seja algo abc algo". A adição do quantificador não-ganancioso ?faz com que o regex corresponda apenas "a qualquer coisa que seja".

Jared Ng
fonte
4
Obrigado, mas o seu um faz incluir o abc no jogo. Em outras palavras, a correspondência resultante é "qualquer coisa que seja abc".
Callum
1
Você poderia explicar o que finalmente está tentando fazer? Se o seu cenário for: (A) Você deseja obter tudo o que antecede "abc" - use parênteses em torno do que deseja capturar. (B) Você deseja combinar a string com o "abc" - você deve verificar o abc de qualquer maneira, portanto ele precisa fazer parte do regex independentemente. De que outra forma você pode verificar se está lá?
Jared Ng
sedparece não suportar correspondência não gananciosa, nem look-around ( (?=...)). O que mais eu posso fazer? Comando Exemplo: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"retornos two,three, FOUR FIVE, mas espero two,three...
CodeManX
1
@CoDEmanX Você provavelmente deve postar isso como sua própria pergunta separada e não como um comentário, especialmente porque é especificamente sobre sed. Dito isto, para responder à sua pergunta: você pode querer procurar as respostas para esta pergunta . Observe também que, no seu exemplo, um intérprete atento não ganancioso retornaria apenas two, não two,three.
Jared Ng
3
Esta é a forma como cada resposta regexp deve olhar - exemplo e explicação de todas as partes ...
jave.web
54

Como @Jared Ng e @Issun apontaram, a chave para resolver esse tipo de RegEx como "corresponder tudo a uma determinada palavra ou substring" ou "corresponder tudo após uma determinada palavra ou substring" é chamada de asserções de comprimento zero "lookaround" . Leia mais sobre eles aqui.

No seu caso particular, isso pode ser resolvido com um olhar positivo à frente: .+?(?=abc)

Uma imagem vale mais que mil palavras. Veja a explicação detalhada na captura de tela.

Captura de tela do Regex101

Devy
fonte
23
.+?(?=abc)regex de copiar e colar vale mais.
Tom
Que tal excluir espaços à esquerda?
Royi
8

O que você precisa é olhar em volta da afirmação .+? (?=abc).

Veja: Lookahead e Lookbehind Zero-Length Assertions

Esteja ciente de que [abc]não é o mesmo que abc. Entre parênteses, não é uma string - cada caractere é apenas uma das possibilidades. Fora dos colchetes, ele se torna a corda.

aevanko
fonte
7

Para regex em Java, e acredito também na maioria dos mecanismos de regex, se você quiser incluir a última parte, isso funcionará:

.+?(abc)

Por exemplo, nesta linha:

I have this very nice senabctence

selecione todos os caracteres até "abc" e também inclua abc

usando nossa regex, o resultado será: I have this very nice senabc

Teste isso: https://regex101.com/r/mX51ru/1

Dadan
fonte
4

Eu terminei nesta questão de stackoverflow depois de procurar ajuda para resolver o meu problema, mas não encontrei uma solução para ele :(

Então eu tive que improvisar ... depois de algum tempo, consegui alcançar o regex que eu precisava:

insira a descrição da imagem aqui

Como você pode ver, eu precisava de até uma pasta antes da pasta "grp-bps", sem incluir o último traço. E era necessário ter pelo menos uma pasta após a pasta "grp-bps".

Editar

Versão em texto para copiar e colar (altere 'grp-bps' no seu texto):

.*\/grp-bps\/[^\/]+
Loaderon
fonte
6
Nenhuma versão de texto? K
kiradotee 18/02/19
2

Isso fará sentido sobre regex.

  1. A palavra exata pode ser obtida no seguinte comando regex:

("(. *?)") / g

Aqui, podemos obter a palavra exata globalmente que pertence às aspas duplas. Por exemplo, se nosso texto de pesquisa for,

Este é o exemplo das palavras "aspas duplas"

então seremos "citados duas vezes" nessa frase.

Ponmurugan Mohanraj
fonte
Bem-vindo ao StackOverflow e obrigado por sua tentativa de ajudar. No entanto, acho difícil ver como isso ajuda o objetivo indicado na pergunta. Você pode elaborar? Você pode aplicá-lo aos exemplos dados? Você parece se concentrar em lidar com o "que, para mim, parece irrelevante para a questão.
Yunnosch
1
Olá, expliquei como colocar a palavra ou frases entre os caracteres especiais. Aqui nossa pergunta também é "qualquer coisa até a sequência de caracteres especiais". então tentei com aspas duplas e expliquei aqui. Obrigado.
Ponmurugan Mohanraj
2

No python:

.+?(?=abc) funciona para o caso de linha única.

[^]+?(?=abc)não funciona, já que o python não reconhece [^] como regex válido. Para fazer a correspondência multilinha funcionar, você precisará usar a opção re.DOTALL, por exemplo:

re.findall('.+?(?=abc)', data, re.DOTALL)
David Mulder
fonte
0

Eu acredito que você precisa de subexpressões. Se bem me lembro, você pode usar os ()colchetes normais para subexpressões.

Esta parte é do manual grep:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

Faça algo como ^[^(abc)]deve fazer o truque.

Nandhini Anand
fonte
Desculpe, isso não funciona. Colocar o abc entre parênteses não parece fazer nenhuma diferença. Eles ainda são tratados como "a OR b OR c".
Callum
-1

Como $marca o final de uma string, algo assim deve funcionar: [[^abc]*]$onde você está procurando por algo que NÃO TERMINA em qualquer iteração abc, mas teria que estar no final

Além disso, se você estiver usando uma linguagem de script com regex (como php ou js), eles têm uma função de pesquisa que para quando encontra um padrão pela primeira vez (e você pode especificar iniciar da esquerda ou da direita ou com php, você pode implodir para espelhar a string).

jacob
fonte
-6

tente isso

.+?efg

Inquerir :

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

resultado :

hijklmn
Balakrishna Gondesi
fonte