Estou tentando criar um comando sed usando regex para substituir algo em um arquivo de texto somente se ele não for comentado, mas estou tendo alguns problemas devido ao meu conhecimento quase inexistente dos comandos do sed. / p>
Encontrei soluções para pequenas partes do problema, mas algumas não estão completas o suficiente ou simplesmente não consigo colocá-las juntas. TL; versão do DR disponível no final.
Vamos primeiro determinar meu objetivo final
Gostaria de corresponder qualquer coisa (como qualquer regular regex (hehe)) em um arquivo de texto somente se NÃO for comentado. Como eu gostaria de fazer isso para vários idiomas, vamos apenas pegar os comentários comuns do C.
Portanto, neste caso, palavras ou linhas podem ser comentadas de maneiras diferentes. Temos o //
para comentar somente o que vem a seguir na linha e também temos o bloco /* */
comment.
Ambiente
Atualmente estou trabalhando no Mac OSX que suporta apenas o POSIX sed, mas instalei um GNU-sed que acho melhor. (Obrigado a Homebrew
. O pacote é gnu-sed
e o comando é gsed
.) Então, ambos estão disponíveis para mim se você preferir usar um ou outro.
Eu estou escrevendo isso assumindo que um GNU-sed é usado.
Ignorando um caso
Primeiro problema, como ignorar alguns casos. Eu achei isso facilmente em este tópico .
Agora, a parte //
parece fácil para mim e eu teria que adicionar uma condição OR ( |
) para associá-la à outra condição.
Seria algo parecido com isto:
sed -E "/\/\/.*/! s/foo/bar/" file
Então, se o arquivo de entrada for:
foo
42
test
//foo
//42
// foo
//something foo
foo
42
something foo
foo
A saída é:
bar
42
test
//foo
//42
// foo
//something foo
bar
42
something bar
bar
Então, agora, vou concentrar minha reflexão apenas no bloco /* */
comment.
Correspondendo por várias linhas
Segundo problema, como fazer a regex combinar através de várias linhas. Bem, acho que esse é o maior problema. Eu encontrei este tópico falando sobre como combinar através de apenas um novo caractere de linha. Bem, levei um momento para entender como funciona. Mas essa parte da solução me traz um novo problema e novas perguntas.
Obviamente, ele pode ignorar apenas uma nova linha ( \n
). Então agora eu quero fazer o mesmo, mas para um número desconhecido de linhas (de 0 a infinito ( *
)). Aposto que tenho que passar pelas linhas, mas é aí que estou preso porque não sei nada sobre os comandos do sed e é realmente estranho para mim.
Durante minhas pesquisas, encontrei um pequeno script com o objetivo de substituir o tail
comando e usa um loop (eu acho), mas não consigo entender o seu funcionamento.
Faça com que ele corresponda apenas antes da parte */
A terceira parte é garantir que o caso ignorado corresponda apenas ao final do bloco de comentários ( */
). Portanto, no final, o caso de ignorar corresponderia apenas as coisas entre /*
e */
. O comando final, então, ignoraria completamente as coisas escritas dentro de um bloco de comentários.
Eu não fiz uma pesquisa real sobre essa parte, pois não resolvi o ponto anterior e parece-me que esse problema */
depende do problema anterior /*
.
Parte final: juntando tudo isso
Bem, é óbvio que eu falhei completamente nisso no momento.
TL; DR
Minha pergunta é: qual seria o comando sed para substituir qualquer coisa que desejássemos em um arquivo de texto somente se não fosse comentado?
Apêndice
Se você conhece uma maneira mais fácil de fazer isso, usando qualquer outro idioma, também é muito bem-vindo. Então, se você souber como fazer isso com awk
, python
ou qualquer outra coisa, sinta-se à vontade para compartilhá-lo.