converte comentários no estilo C para o estilo C ++ usando sed

5

Estou tentando converter comentários no estilo 'C' de linha única para o estilo 'C ++'. O 'sed' abaixo não é ruim, mas é claro que ele falha se qualquer código principal (código antes do comentário) tiver algum '/' nele:

sed -i 's,\(^[^\/]*\)\/\*\([^\*]*\)\*\/[ ]*$,\/\/,' filename

O que eu gostaria de poder fazer é isto:

... [^\/\*] ...

i.e. negate '/ *' que não funciona, claro, mas depois de várias horas de pesquisa, não consigo encontrar uma explicação simple de como fazer isso corretamente :( Não parece deve ser ciência de foguetes.

Por exemplo, estas sequências:

blah blah        /* comment */
blah blah / blah /* comment */
blah blah        /* comment */ blah
blah blah / blah /* comment */ blah 

... deve converter-se assim:

blah blah        // comment 
blah blah / blah // comment 
blah blah        /* comment */ blah  (this CAN'T be converted)
blah blah / blah /* comment */ blah  (this CAN'T be converted)

... obviamente nenhuma conversão pode ocorrer se houver código APÓS o comentário 'C'.

Eu farei uma comparação visual próxima entre o arquivo, antes e depois, então não há necessidade de manipular '/ *' dentro de um literal, nem quero converter qualquer coisa em multi-linha.

Note que eu penso nisso como um problema de 'negação', mas talvez haja outra maneira. Eu só preciso capturar tudo antes de um '/ *' e não me importa como.

ACOMPANHE A RESPOSTA ABAIXO

Bem, droga! Eu vejo que eu entendi completamente algo fundamental:

.*/\*

... lê: "qualquer coisa exceto slash star seguido por slash star", então na verdade eu recebo minha 'negação' de graça :-)

Então, indo ainda mais longe do que Barmar:

sed -i 's,^\(.*\)/\*\(.*\)\*/\s*$,//,' filename

... vai perceber isso:

blah / * blah        /* co / mme * nt */

e imprima isto:

blah / * blah       // co / mme * nt 

Iluminismo.

    
por Ray Andrews 22.10.2014 / 21:11

2 respostas

3

Tente isto:

sed 's,^\(.*\)/\*\([^/]*\)\*/$,//,'

Isso não converterá comentários que contenham caracteres / incorporados. Como alternativa, você pode usar:

sed 's,^\(.*\)/\*\(.*\)\*/$,//,'

Isso fará a coisa errada se você tiver dois comentários na mesma linha, por exemplo

blah blah        /* comment1 */ blah /* comment2 */

será convertido para

blah blah       // comment1 */ blah /* comment2

Pode ser possível fazer melhor com uma versão PCRE de sed , pois você pode usar uma visão negativa para testar comentários incorporados.

Note também que usar , como o delimitador no comando s significa que você não precisa escapar todos os caracteres / no regexp - esse é o ponto de usar algum caractere diferente de / como o delimitador quando o regexp contém muitos / .

    
por 22.10.2014 / 23:39
2

Provavelmente, a maneira mais segura é testar primeiro as linhas que você não deseja afetar e b ranch do script se você tiver uma correspondência.

sed '\|\*/.*/\*|b'

Isso é um pouco difícil de ler com todas as * estrelas lá, mas basicamente se /* ocorrer após */ sed sair da execução do script, imprimir automaticamente a linha e puxar a próxima linha para começar o próximo ciclo de linha. Todos os comandos seguintes não são executados para uma linha correspondente.

Outra maneira de fazer isso é com t est, que será similarmente b ranch de um script se não receber nenhum rótulo b ranch após uma s/// ubstitution bem-sucedida:

sed 's|/\*|&|2;t'

Isso tenta substituir a segunda ocorrência do padrão na linha por si mesma e, se for bem-sucedida, se ramifica da mesma maneira que b faz.

E então ...

sed 's|/\*|&|2;s|\*/|&|2;t
     s|/\*\(.*\)\*/ *$|//|'

... substituirá a primeira e única ocorrência de /* com // nas linhas que terminam com a primeira e única ocorrência de */ e qualquer quantidade de caracteres de espaço à direita. Isso funciona porque t se aplica a qualquer substituição ocorrendo antes dela e, portanto, se um ou outro t ests for bem-sucedido, sed será ramificado.

Pode ser que eu tenha cometido um erro aqui, já que não estou muito familiarizado com C ou C ++ e não tenho certeza do que pode acontecer em um caso /\*.*\*/.*\*/ - do qual o script acima b se distancia. Talvez você deva testar apenas 2 */ ou apenas 2 /* . Espero que, pelo menos, eu tenha conseguido transmitir o conceito para quem sabe melhor.

    
por 23.10.2014 / 09:55

Tags