Usando bash para reformatar “#include” em uma lista de arquivos usando regex

1

Considere o seguinte código que faz um simples loop sobre arquivos de código:

#!/bin/bash
dir="."
find $dir -name *.cpp -o -name *.h | while read file; do
    echo "processing: "$file
    # Process file here
done

Todos os arquivos iniciados com o messy são incluídos como este

#include<iostream>
#include <vector>
#include"this_is_file1.h"
#include "this_is_file2.h"
#include "This_Is_File3.h"
#include"thisIsFile4.h"
#include "ThisIsFile5.h"
#include"dir/thisIsFile6.h"
#include "dir/ThisIsFile7.h"
#include "dir/ThisIsFile8.txx"
#include "dir/ThisIsFILe9.txx"

que eu gostaria de transformar assim (e substituir o arquivo antigo)

#include <iostream>
#include <vector>
#include "this_is_file1.h"
#include "this_is_file2.h"
#include "this_is_file3.h"
#include "this_is_file4.h"
#include "this_is_file5.h"
#include "this_is_file6.h"
#include "this_is_file7.h"
#include "this_is_file8.txx"
#include "this_is_file9.txx"

Mais formalmente:

  • Deve haver exatamente um espaço entre o include e o nome do arquivo
  • Não deve haver nenhuma letra maiúscula, e cada seqüência consecutiva de maiúsculas que foram substituídas deve ser precedida por exatamente um sublinhado, exceto se for o início do nome do arquivo
  • Não deve haver nenhum nome de diretório

Como fazer isso com o bash?

    
por Vincent 05.02.2017 / 19:00

3 respostas

4

O seguinte script sed deve fazer isso:

s/\(#include\) *\([^ ]\+\)/ /

/^#include "/ {
    s/".*\//"/
    s/"\(.\)/"\l/g
    s/\([^A-Z]\)\([A-Z]\)/_\l/g
    s/_\+/_/g
}

Isso pode ser aplicado aos arquivos em execução:

sed -i.bak -f fix.sed input...

(Isso pressupõe que o script acima é chamado fix.sed e qualquer número de arquivos pode ser dado como argumentos depois. Remova .bak se você não quiser que nenhum backup seja criado.

A primeira expressão de substituição de sed corresponde a #include seguido por uma possivelmente uma execução vazia de espaços ( \ * ) e substitui essa execução por espaço único. Ele também transforma o restante da linha ( [^ ]\+ ) em minúsculas (usando \l ).

As próximas quatro expressões sed, todas as quais se aplicam apenas a linhas que comece com #include " , faça o seguinte:

  1. Nome do caminho da faixa (tudo até e incluindo a última barra);

  2. transforme o primeiro caractere entre aspas em minúsculas;

  3. no início de cada execução de letras maiúsculas, insira sublinhado e transformar o primeiro caractere de executar em minúsculas;

  4. execuções de squeeze de sublinhado possivelmente inseridas pelas etapas anteriores.

Isto é imperfeito, mas traduz o seu exemplo de entrada como pretendido.

    
por 05.02.2017 / 19:15
0

Você pode achar que o uso de uma ferramenta como astyle formata seu código corretamente e faz mais do que apenas consertar as #include linhas .

Seu código está bem, como está, mas se você não tem espaços em seus nomes de arquivos ou outras esquisitices, você pode usar find :

astyle --style=allman -A1 --indent=spaces=4  \
   --break-blocks --pad-oper --pad-header --unpad-paren \
   --max-code-length=200 \
   $(find . -name '*.cpp' -print) $(find . -name '*.h' -print)
    
por 05.02.2017 / 20:02
0
perl -i.bak -pe '
   if( s!(#include) *(["<])(.*/)?!$1 $2!){  ## if is a include line
        s/(?<=[a-z])(?=[A-Z])/_/g;          ##   insert CamelCase "_"
        tr/A-Z/a-z/ }'   file               ##   lowercase ids
    
por 05.02.2017 / 20:37