Expressão regular para corresponder a uma linha que não contém uma palavra?

Eu sei que é possível combinar uma palavra e depois inverter as partidas usando outras ferramentas (por exemplo, grep -v ). No entanto, eu gostaria de saber se é possível combinar linhas que não contenham uma palavra específica (por exemplo, hede) usando uma expressão regular.

Entrada:

 hoho hihi haha hede 

Código:

 grep "" input 

Saída desejada:

 hoho hihi haha 

A noção de que regex não suporta correspondência inversa não é inteiramente verdadeira. Você pode imitar esse comportamento usando look-arounds negativos:

 ^((?!hede).)*$ 

O regex acima corresponderá a qualquer string, ou linha sem quebra de linha, não contendo a string (sub) ‘hede’. Como mencionado, isso não é algo que o regex é “bom” (ou deveria fazer), mas ainda assim é possível.

E se você precisar combinar também os caracteres de quebra de linha, use o modificador DOT-ALL (o trailing s no seguinte padrão):

 /^((?!hede).)*$/s 

ou use-o em linha:

 /(?s)^((?!hede).)*$/ 

(onde o /.../ são os delimitadores regex, ou seja, não fazem parte do padrão)

Se o modificador DOT-ALL não estiver disponível, você pode imitar o mesmo comportamento com a class de caracteres [\s\S] :

 /^((?!hede)[\s\S])*$/ 

Explicação

Uma string é apenas uma lista de n caracteres. Antes e depois de cada personagem, há uma string vazia. Portanto, uma lista de n caracteres terá n+1 sequências vazias. Considere a string "ABhedeCD" :

  ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐ S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│ └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘ index 0 1 2 3 4 5 6 7 

onde os e são cordas vazias. O regex (?!hede). olha em frente para ver se não há substring "hede" para ser visto, e se for esse o caso (então algo mais é visto), então o . (ponto) corresponderá a qualquer caractere, exceto uma quebra de linha. Look-arounds também são chamados de asserções de largura zero porque não consomem nenhum caractere. Eles apenas afirmam / validam algo.

Então, no meu exemplo, cada string vazia é validada primeiro para ver se não há "hede" à frente, antes que um caractere seja consumido pelo . (ponto). O regex (?!hede). fará isso apenas uma vez, por isso é empacotado em um grupo e repetido zero ou mais vezes: ((?!hede).)* . Finalmente, o início e o fim da input são ancorados para garantir que toda a input seja consumida: ^((?!hede).)*$

Como você pode ver, a input "ABhedeCD" falhará porque no e3 , o regex (?!hede) falha (há "hede" à frente!).

Note que a solução não começa com “hede” :

 ^(?!hede).*$ 

geralmente é muito mais eficiente do que a solução não contém “hede” :

 ^((?!hede).)*$ 

O primeiro verifica “hede” apenas na primeira posição da string de input, e não em todas as posições.

Se você está apenas usando para grep, você pode usar grep -v hede para obter todas as linhas que não contenham hede.

ETA Oh, relendo a pergunta, grep -v é provavelmente o que você entende por “opções de ferramentas”.

Responda:

 ^((?!hede).)*$ 

Explicação:

^ o início da string, ( agrupe e capture para \ 1 (0 ou mais vezes (correspondendo a maior quantidade possível)),
(?! olhe para frente para ver se não há,

hede sua corda,

final de olhar para frente . qualquer caractere, exceto \ n,
)* fim de \ 1 (Nota: porque você está usando um quantificador nesta captura, somente a repetição ÚLTIMA do padrão capturado será armazenada em \ 1)
$ antes de um opcional \ n e o final da string

As respostas dadas são perfeitamente bem, apenas um ponto acadêmico:

Expressões regulares no sentido de teóricas ciências da computação não são capazes de fazê-lo assim. Para eles, tinha que parecer algo assim:

 ^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

Isso só faz uma correspondência COMPLETA. Fazê-lo para sub-partidas seria ainda mais complicado.

Se você quiser que o teste de regex falhe somente se a string inteira corresponder, o seguinte funcionará:

 ^(?!hede$).* 

eg – Se você quiser permitir que todos os valores, exceto “foo” (isto é, “foofoo”, “barfoo” e “foobar” passem, mas “foo” falhará, use: ^(?!foo$).*

É claro que, se você estiver verificando a igualdade exata , uma solução geral melhor, nesse caso, é verificar a igualdade da cadeia, ou seja,

 myStr !== 'foo' 

Você pode até mesmo colocar a negação fora do teste se precisar de resources de regex (aqui, insensibilidade a maiúsculas e variações de correspondência):

 !/^[af]oo$/i.test(myStr) 

A solução de regex no topo pode ser útil, no entanto, em situações em que um teste de regex positivo é necessário (talvez por uma API).

Aqui está uma boa explicação de por que não é fácil negar um regex arbitrário. Eu tenho que concordar com as outras respostas, porém: se isso é outra coisa senão uma pergunta hipotética, então um regex não é a escolha certa aqui.

FWIW, uma vez que linguagens regulares (aka linguagens racionais) são fechadas sob complementação, é sempre possível encontrar uma expressão regular (também conhecida como expressão racional) que negue outra expressão. Mas muitas ferramentas não implementam isso.

Vcsn suporta este operador (que denota {c} , postfix).

Primeiro você define o tipo de suas expressões: labels são letra ( lal_char ) para escolher de lal_char por exemplo (definir o alfabeto ao trabalhar com complementação é, é claro, muito importante), e o “valor” computado para cada palavra é apenas um booleano: true a palavra é aceita, false , rejeitada.

Em Python:

 In [5]: import vcsn c = vcsn.context('lal_char(az), b') c Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} → 𝔹 

então você digita sua expressão:

 In [6]: e = c.expression('(hede){c}'); e Out[6]: (hede)^c 

Converta esta expressão para um autômato:

 In [7]: a = e.automaton(); a 

O autômato correspondente

finalmente, converta este autômato de volta em uma expressão simples.

 In [8]: print(a.expression()) \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]* 

onde + geralmente é denotado | , \e denota a palavra vazia e [^] é geralmente escrito . (qualquer personagem). Então, com um pouco de reescrita ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).* .

Você pode ver este exemplo aqui e tentar o Vcsn online lá .

Referências

Eu decidi avaliar algumas das opções apresentadas e comparar seu desempenho, bem como usar alguns novos resources. Benchmarking no .NET Regex Engine: http://regexhero.net/tester/

Texto de referência:

As primeiras 7 linhas não devem corresponder, pois elas contêm a Expressão pesquisada, enquanto as 7 linhas inferiores devem corresponder!

 Regex Hero is a real-time online Silverlight Regular Expression Tester. XRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester. RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her egex Hero egex Hero is a real-time online Silverlight Regular Expression Tester. Regex Her is a real-time online Silverlight Regular Expression Tester. Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester. Nobody is a real-time online Silverlight Regular Expression Tester. Regex Her o egex Hero Regex Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester. 

Resultados:

Os resultados são iterações por segundo como a mediana de 3 execuções – Número Maior = Melhor

 01: ^((?!Regex Hero).)*$ 3.914 // Accepted Answer 02: ^(?:(?!Regex Hero).)*$ 5.034 // With Non-Capturing group 03: ^(?>[^R]+|R(?!egex Hero))*$ 6.137 // Lookahead only on the right first letter 04: ^(?>(?:.*?Regex Hero)?)^.*$ 7.426 // Match the word and check if you're still at linestart 05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$ 7.371 // Logic Branch: Find Regex Hero? match nothing, else anything P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT)) ????? // Logic Branch in Perl - Quick FAIL P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ????? // Direct COMMIT & FAIL in Perl 

Como o .NET não suporta Verbos de ação (* FAIL, etc.) eu não pude testar as soluções P1 e P2.

Resumo:

Eu tentei testar a maioria das soluções propostas, algumas otimizações são possíveis para certas palavras. Por exemplo, se as duas primeiras letras da string de pesquisa não forem iguais, a resposta 03 pode ser expandida para ^(?>[^R]+|R+(?!egex Hero))*$ resultando em um pequeno ganho de desempenho.

Mas a solução mais rápida e mais legível em termos de desempenho parece ser 05 usando uma instrução condicional ou 04 com o quantificador possuidor. Eu acho que as soluções Perl devem ser ainda mais rápidas e mais fáceis de ler.

Com lookahead negativo, a expressão regular pode corresponder a algo que não contém um padrão específico. Isto é respondido e explicado por Bart Kiers. Grande explicação!

No entanto, com a resposta de Bart Kiers, a parte de lookahead testará de 1 a 4 caracteres à frente, enquanto combina com qualquer caractere individual. Podemos evitar isso e deixar que a parte lookahead verifique todo o texto, certifique-se de que não há ‘hede’, e então a parte normal (. *) Pode consumir todo o texto de uma só vez.

Aqui está o regex melhorado:

 /^(?!.*?hede).*$/ 

Note que o quantificador preguiçoso (*?) Na parte lookahead negativa é opcional, você pode usar quantificador guloso em vez disso, dependendo de seus dados: se ‘hede’ estiver presente e na metade inicial do texto, o quantificador lento pode seja mais rápido; caso contrário, o quantificador ganancioso será mais rápido. No entanto, se ‘hede’ não estiver presente, ambos serão lentos.

Aqui está o código de demonstração .

Para mais informações sobre lookahead, confira o ótimo artigo: Mastering Lookahead e Lookbehind .

Além disso, confira o RegexGen.js , um Gerador de Expressões Regulares do JavaScript que ajuda a construir expressões regulares complexas. Com o RegexGen.js, você pode construir o regex de uma forma mais legível:

 var _ = regexGen; var regex = _( _.startOfLine(), _.anything().notContains( // match anything that not contains: _.anything().lazy(), 'hede' // zero or more chars that followed by 'hede', // ie, anything contains 'hede' ), _.endOfLine() ); 

Não é regex, mas achei lógico e útil usar greps seriais com pipe para eliminar o ruído.

por exemplo. procurar um arquivo de configuração do apache sem todos os comentários-

 grep -v '\#' /opt/lampp/etc/httpd.conf # this gives all the non-comment lines 

e

 grep -v '\#' /opt/lampp/etc/httpd.conf | grep -i dir 

A lógica do grep serial é (não é um comentário) e (corresponde ao dir)

Com isso, você evita testar um lookahead em cada posição:

 /^(?:[^h]+|h++(?!ede))*+$/ 

equivalente a (para .net):

 ^(?>(?:[^h]+|h+(?!ede))*)$ 

Resposta antiga:

 /^(?>[^h]+|h+(?!ede))*$/ 

Aqui está como eu faria:

 ^[^h]*(h(?!ede)[^h]*)*$ 

Exato e mais eficiente que as outras respostas. Ele implementa a técnica de eficiência “desenrolando-o-laço” de Friedl e requer muito menos retrocesso.

(?:(?!hede).)* É ótimo porque pode ser ancorado.

 ^(?:(?!hede).)*$ # A line without hede foo(?:(?!hede).)*bar # foo followed by bar, without hede between them 

Mas o seguinte seria suficiente neste caso:

 ^(?!.*hede) # A line without hede 

Essa simplificação está pronta para include cláusulas “AND”:

 ^(?!.*hede)(?=.*foo)(?=.*bar) # A line with foo and bar, but without hede ^(?!.*hede)(?=.*foo).*bar # Same 

Se você quiser combinar um caractere para negar uma palavra similar a negar class de caractere:

Por exemplo, uma string:

 < ? $str="aaa bbb4 aaa bbb7"; ?> 

Não use:

 < ? preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches); ?> 

Usar:

 < ? preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches); ?> 

Observe "(?!bbb)." não é lookbehind nem lookahead, é lookcurrent, por exemplo:

 "(?=abc)abcde", "(?!abc)abcde" 

O OP não especificou ou marcou o post para indicar o contexto (linguagem de programação, editor, ferramenta) no qual o Regex será usado.

Para mim, às vezes preciso fazer isso durante a edição de um arquivo usando o Textpad .

Textpad suporta alguns Regex, mas não suporta lookahead ou lookbehind, por isso, leva alguns passos.

Se eu hede manter todas as linhas que NÃO contêm o string hede , eu faria assim:

1. Procure / substitua o arquivo inteiro para adicionar uma “Tag” exclusiva ao início de cada linha contendo qualquer texto.

  Search string:^(.) Replace string:< @#-unique-#@>\1 Replace-all 

2. Exclua todas as linhas que contêm o hede da cadeia (a cadeia de substituição está vazia):

  Search string:< @#-unique-#@>.*hede.*\n Replace string: Replace-all 

3. Neste ponto, todas as linhas restantes NÃO contêm o fio hede . Remova o “Tag” exclusivo de todas as linhas (a string de substituição está vazia):

  Search string:< @#-unique-#@> Replace string: Replace-all 

Agora você tem o texto original com todas as linhas contendo a string hede removida.


Se eu estou olhando para fazer algo mais para apenas as linhas que não contêm a string hede , eu faria assim:

1. Procure / substitua o arquivo inteiro para adicionar uma “Tag” exclusiva ao início de cada linha contendo qualquer texto.

  Search string:^(.) Replace string:< @#-unique-#@>\1 Replace-all 

2. Para todas as linhas que contenham o hede da string, remova a “Tag” exclusiva:

  Search string:< @#-unique-#@>(.*hede) Replace string:\1 Replace-all 

3. Neste ponto, todas as linhas que começam com a “Tag” exclusiva NÃO contêm o string hede . Agora posso fazer o meu algo mais para apenas essas linhas.

4. Quando terminar, removerei a “Tag” exclusiva de todas as linhas (a string de substituição está vazia):

  Search string:< @#-unique-#@> Replace string: Replace-all 

Através do verbo PCRE (*SKIP)(*F)

 ^hede$(*SKIP)(*F)|^.*$ 

Isso hede completamente a linha que contém o hede string exato e corresponde a todas as linhas restantes.

DEMO

Execução das partes:

Vamos considerar o regex acima, dividindo-o em duas partes.

  1. Parte antes do | símbolo. Parte não deve ser correspondida .

     ^hede$(*SKIP)(*F) 
  2. Parte após o | símbolo. Parte deve ser correspondida .

     ^.*$ 

PARTE 1

O mecanismo de regex iniciará sua execução a partir da primeira parte.

 ^hede$(*SKIP)(*F) 

Explicação:

  • ^ Afirma que estamos no começo.
  • hede Corresponde à corda hede
  • $ Afirma que estamos no final da linha.

Portanto, a linha que contém o string hede seria correspondida. Uma vez que o mecanismo de regex veja o seguinte (*SKIP)(*F) ( Nota: Você pode escrever (*F) como (*FAIL) ) verbo, pula e faz a correspondência falhar. | chamada de alteração ou operador OR lógico adicionado ao lado do verbo PCRE, que corresponde a todos os limites existentes entre cada caractere em todas as linhas, exceto que a linha contém o hede string exato. Veja a demonstração aqui . Ou seja, ele tenta corresponder os caracteres da string restante. Agora o regex na segunda parte seria executado.

PARTE 2

 ^.*$ 

Explicação:

  • ^ Afirma que estamos no começo. isto é, corresponde a todos os inícios de linha, exceto o da linha de hede . Veja a demonstração aqui .
  • .* No modo Multilinha . corresponderia a qualquer caractere, exceto caracteres de nova linha ou caracteres de retorno. E * repetiria o caractere anterior zero ou mais vezes. Então, .* corresponderia à linha inteira. Veja a demonstração aqui .

    Ei, por que você adicionou. * Em vez de. +?

    Porque .* Corresponderia a uma linha em branco, mas .+ não corresponderá a um espaço em branco. Queremos combinar todas as linhas, exceto hede , pode haver a possibilidade de linhas em branco também na input. então você deve usar .* invés de. .+ repetiria o caractere anterior uma ou mais vezes. Veja .* Corresponde a uma linha em branco aqui .

  • $ Fim da linha de âncora não é necessário aqui.

Desde a introdução do ruby-2.4.1, podemos usar o novo Operador Ausente nas Expressões Regulares do Ruby

do documento oficial

 (?~abc) matches: "", "ab", "aab", "cccc", etc. It doesn't match: "abc", "aabc", "ccccabc", etc. 

Assim, no seu caso ^(?~hede)$ faz o trabalho para você

 2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)} => ["hoho", "hihi", "haha"] 

Como ninguém mais deu uma resposta direta à pergunta que foi feita , farei isso.

A resposta é que, com o POSIX grep , é impossível literalmente satisfazer essa solicitação:

 grep "Regex for doesn't contain hede" Input 

A razão é que o POSIX grep só é necessário para trabalhar com Basic Regular Expressions , que simplesmente não são poderosas o suficiente para realizar essa tarefa (elas não são capazes de analisar linguagens regulares, devido à falta de alternância e agrupamento).

No entanto, o GNU grep implementa extensões que permitem isso. Em particular, \| é o operador de alternância na implementação de BREs do GNU, e \( e \) são os operadores de agrupamento. Se o seu mecanismo de expressões regulares suportar alternância, expressões de colchetes negativos, agrupamento e a estrela de Kleene, e for capaz de ancorar no início e no final da cadeia, isso é tudo o que você precisa para essa abordagem.

Com o GNU grep , seria algo como:

 grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" Input 

(encontrado com o Graal e algumas outras otimizações feitas à mão).

Você também pode usar uma ferramenta que implemente expressões regulares estendidas , como egrep , para se livrar das barras invertidas:

 egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" Input 

Aqui está um script para testá-lo (note que gera um arquivo testinput.txt no diretório atual):

 #!/bin/bash REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" # First four lines as in OP's testcase. cat > testinput.txt <  

No meu sistema, imprime:

 Files /dev/fd/63 and /dev/fd/62 are identical 

como esperado.

Para aqueles interessados ​​nos detalhes, a técnica empregada é converter a expressão regular que combina a palavra em um autômato finito, depois inverter o autômato mudando todo estado de aceitação para não-aceitação e vice-versa, e então convertendo o FA resultante de volta para uma expressão regular.

Por fim, como todos notaram, se o seu mecanismo de expressões regulares oferecer suporte a lookahead negativo, isso simplifica muito a tarefa. Por exemplo, com o GNU grep:

 grep -P '^((?!hede).)*$' Input 

Update: Eu encontrei recentemente a excelente biblioteca FormalTheory do Kendall Hopkins, escrita em PHP, que fornece uma funcionalidade similar ao Grail. Usando-o e um simplificador escrito por mim, consegui escrever um gerador on-line de expressões regulares negativas com uma frase de input (apenas caracteres alfanuméricos e de espaço atualmente suportados): http://www.formauri.es/personal/ pgimeno / misc / non-match-regex /

Para hede , o resultado é:

 ^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$ 

que é equivalente ao acima.

Pode ser mais fácil manter dois regexes em seu código, um para fazer a primeira correspondência e, se ele corresponder, executar o segundo regex para verificar se há casos discrepantes que você deseja bloquear, por exemplo ^.*(hede).* lógica em seu código.

OK, I admit this is not really an answer to the posted question posted and it may also use slightly more processing than a single regex. But for developers who came here looking for a fast emergency fix for an outlier case then this solution should not be overlooked.

The TXR Language supports regex negation.

 $ txr -c '@(repeat) @{nothede /~hede/} @(do (put-line nothede)) @(end)' Input 

A more complicated example: match all lines that start with a and end with z , but do not contain the substring hede :

 $ txr -c '@(repeat) @{nothede /a.*z&~.*hede.*/} @(do (put-line nothede)) @(end)' - az < - echoed az abcz <- echoed abcz abhederz <- not echoed; contains hede ahedez <- not echoed; contains hede ace <- not echoed; does not end in z ahedz <- echoed ahedz 

Regex negation is not particularly useful on its own but when you also have intersection, things get interesting, since you have a full set of boolean set operations: you can express "the set which matches this, except for things which match that".

The below function will help you get your desired output

 < ?PHP function removePrepositions($text){ $propositions=array('/\bfor\b/i','/\bthe\b/i'); if( count($propositions) > 0 ) { foreach($propositions as $exceptionPhrase) { $text = preg_replace($exceptionPhrase, '', trim($text)); } $retval = trim($text); } return $retval; } ?> 

A simpler solution is to use the not operator !

Your if statement will need to match “contains” and not match “excludes”.

 var contains = /abc/; var excludes =/hede/; if(string.match(contains) && !(string.match(excludes))){ //proceed... 

I believe the designers of RegEx anticipated the use of not operators.

How to use PCRE’s backtracking control verbs to match a line not containing a word

Here’s a method that I haven’t seen used before:

 /.*hede(*COMMIT)^|/ 

How it works

First, it tries to find “hede” somewhere in the line. If successful, at this point, (*COMMIT) tells the engine to, not only not backtrack in the event of a failure, but also not to attempt any further matching in that case. Then, we try to match something that cannot possibly match (in this case, ^ ).

If a line does not contain “hede” then the second alternative, an empty subpattern, successfully matches the subject string.

This method is no more efficient than a negative lookahead, but I figured I’d just throw it on here in case someone finds it nifty and finds a use for it for other, more interesting applications.

Maybe you’ll find this on Google while trying to write a regex that is able to match segments of a line (as opposed to entire lines) which do not contain a substring. Tooke me a while to figure out, so I’ll share:

Given a string: barfoobaz

I want to match tags which do not contain the substring “bad”.

/ will match and .

Notice that there are two sets (layers) of parentheses:

  • The innermost one is for the negative lookahead (it is not a capture group)
  • The outermost was interpreted by Ruby as capture group but we don’t want it to be a capture group, so I added ?: at it’s beginning and it is no longer interpreted as a capture group.

Demo in Ruby:

 s = 'barfoobaz' s.scan(//) # => ["", ""] 

I don’t understand the need for complex regex or even lookaheads here :

 /hede|^(.*)$/gm 

Don’t put in a capturing group the thing you don’t want, but use one for everything else. This will match all lines that don’t contain “hede”.

With ConyEdit , you can use the command line cc.gl !/hede/ to get lines that do not contain the regex matching, or use the command line cc.dl /hede/ to delete lines that contain the regex matching. They have the same result.