Imprime referência reversa na expressão regular

6

Eu estava esperando uma maneira de fazer sed substituir toda a linha com a substituição (ao invés de apenas a partida) para que eu pudesse fazer algo assim:

sed -e "/$some_complex_regex_with_a_backref//"

e só imprima a referência de volta.

De esta pergunta , parece que a maneira de fazer isso é bagunçar com o regex para coincidir com a linha inteira, ou use alguma outra ferramenta (como perl). Simplesmente alterar o regex para .*regex.* nem sempre funciona (como mencionado nessa pergunta). Por exemplo:

$ echo $regex
\([:alpha:]*\)day

$ echo $phrase
it is Saturday tomorrow

$ echo $phrase | sed "s/$regex//"
it is Satur tomorrow

$ echo $phrase | sed "s/.*$regex.*//"

$ # what I'd like to have happen
$ echo $phrase | [[[some command or string of commands]]]
Satur

Estou procurando a maneira mais concisa de fazer isso, assumindo o seguinte:

  • O regex está em uma variável, portanto não pode ser alterado caso a caso.
  • Gostaria de fazer isso sem usar perl ou outros idiomas mais pesados.
por jakesandlund 16.03.2012 / 22:18

4 respostas

0

Fiz esta pergunta também em SO e recebi esta resposta do potong que faz o que eu estava procurando.

sed '/'"$regex"'/!b;s//\n\n/;s/.*\n\(.*\)\n.*//' file

Observe que não depende do conhecimento do que está em $regex para funcionar. Ele usa novas linhas como um valor sentinela para posteriormente substituir a linha inteira apenas pela referência anterior.

    
por 11.04.2012 / 19:49
3

Eu não sei sed bem o suficiente para responder, mas se você é flexível e usa grep:

grep --only-matching "complex_regex" file

ou

grep -o "complex_regex" file

O sinalizador - only-matching (ou o formato curto -o ) diz ao grep para imprimir apenas a parte correspondente, não toda a linha.

    
por 17.03.2012 / 00:15
0

Seu primeiro. * está parando no "dia", deixando sua referência anterior vazia. Você precisa de algo definido para corresponder antes de seu [[: alpha:]] em sua referência anterior. por exemplo. um espaço,

$ echo $regex
\([[:alpha:]]*\)day

$ echo $phrase
it is Saturday tomorrow

$ echo $phrase | sed "s/.* $regex.*//"
Satur

Eu amo e odeio regexes.

editar:

A extensão não POSIX da palavra limite (\ b) parece capturar os dois casos:

$ regex="\b\([[:alpha:]]\+\)day\b"

Não sei como lidar com a situação em que o padrão aparece várias vezes ou se houver várias palavras no seu padrão.

$ cat phrase.txt
it is Saturday tomorrow
it is   Saturday tomorrow
Saturday is the date tomorrow
        Saturday is the date tomorrow
Saturday is the day tomorrow
        Saturday is the day tomorrow
Saturday is the day in dayton tomorrow
        Saturday is the day in dayton tomorrow
Saturday is the day after Friday
The last day of the week is Friday

$ cat phrase.txt | sed -e "s/.*$regex.*//"
Satur
Satur
Satur
Satur
Satur
Satur
Satur
Satur
Satur
Fri

Estou curioso para saber se alguém que tem mais sed-fu dá uma resposta melhor. : -)

    
por 17.03.2012 / 01:03
0

Isso está próximo da resposta do mgjk, mas com uma abordagem ligeiramente diferente da correspondência de limites.

echo $phrase | sed 's/.*[^[:alpha:]]\([[:alpha:]]*\)day.*//'
Satur

Como .* engolirá qualquer coisa, você terá que primeiro corresponder " não o caractere que eu quero" e "o caractere que eu quero". Então, em $regex você pode armazenar

[^[:alpha:]]\([[:alpha:]]*\)day

Não é sem peculiaridades (não funciona na sua forma atual se "Sábado" é o primeiro na linha), mas se você estiver usando apenas sed ao invés de ferramentas mais potentes, então pode ser suficiente para você . Você também pode fazer isso com um regex de duas partes para resolver o problema do "início da linha", mas então ele está começando a ficar mais complexo novamente, o que você não quer. Se seus critérios mudarem, muitas soluções existem.

    
por 11.04.2012 / 17:16

Tags