Contagem de linhas maiores que 80 colunas, levando as guias corretamente em conta

7

Para contar linhas com mais de 80 colunas, estou usando atualmente este comando:

$ git grep -h -c -v '^.\{,80\}$' **/*.{c,h,p{l,y}} \
    |awk 'BEGIN { i=0 } { i+=$1 } END { printf ("%d\n", i) }'
44984

Infelizmente, o repositório usa guias para recuo, de modo que o padrão grep é impreciso. Existe alguma maneira de ter as guias regex treat no largura padrão de 8 caracteres como como wc -L faz?

Para o propósito desta questão, podemos supor que os colaboradores foram disciplinados o suficiente para recuar consistentemente, ou que eles têm git commit ganchos em vez de disciplina.

Por motivos relacionados ao desempenho, prefiro uma solução que funcione dentro git-grep(1) ou talvez outra ferramenta grep , sem pré-processar arquivos .

    
por phg 14.09.2018 / 09:26

4 respostas

8

Se pudermos supor, por seu comentário, que os caracteres tab aparecerão apenas no início das linhas, então podemos contar alternativas para um mínimo de 80 caracteres.

  • Nenhuma guia, pelo menos 81 caracteres
  • Uma guia com pelo menos 73 caracteres
  • Duas guias, pelo menos 65 caracteres
  • Etc.

A confusão resultante é a seguinte, com sua declaração awk somando as contagens de linha individuais para fornecer um total geral

git grep -hcP '^(.{81,}|\t.{73,}|\t{2}.{65,}|\t{3}.{57,}|\t{4}.{49,}|\t{5}.{41,}|\t{6}.{33,}|\t{7}.{25,}|\t{8}.{17,}|\t{9}.{9,}|\t{10}.)' **/*.{c,h,p{l,y}} |
    awk '{ i+=$1 } END { printf ("%d\n", i) }'
    
por 14.09.2018 / 11:17
12

Pré-processe os arquivos, passando-os por expand . O utilitário expand expandirá as guias apropriadamente (usando as paradas de tabulação padrão a cada oitavo caractere).

find . -type f \( -name '*.[ch]' -o -name '*.p[ly]' \) -exec expand {} + |
awk 'length > 80 { n++ } END { print n }'
    
por 14.09.2018 / 09:50
10

GNU wc -L não trata TABs como 8 caracteres, ele trata TABs como seriam exibidos em um terminal com TAB pára a cada 8 colunas, então teria uma "largura" variando de 1 a 8 caracteres, dependendo de onde eles é encontrado na linha. wc -L também considera a largura de exibição de outros caracteres (se eles têm 0, 1 ou 2 colunas de largura) e também processa \f e \r "corretamente".

$ printf 'abcde\t\n' | wc -L
8

Aqui, você pode usar expand (que por padrão também assume paradas de tabulação a cada 8 colunas, embora você possa alterá-lo com opções) para expandir essas TABs para espaços:

git grep -h '' ./**/*.{c,h,p{l,y}} | expand | tr '\f\r' '\n\n' | grep -cE '.{81}'

(convertendo os CRs (que quando enviados para um terminal movem o cursor de volta para o início da linha) e FFs (que alguns dispositivos de exibição entendem como quebra de página) para LF para obter o mesmo comportamento que wc -L , mas ignorando os outros que, de qualquer forma, não podemos dizer que influência eles terão na largura da tela).

Isso abrange as guias, mas não os caracteres de largura simples ou dupla. Observe que a implementação GNU de expand atualmente não expande as TABs adequadamente se houver caracteres de múltiplos bytes (sem falar nos de largura zero ou de largura dupla).

$ printf 'ééééé\t\n' | wc -L
8
$ printf 'ééééé\t\n' | expand | wc -L
11

Observe também que ./**/*.{c,h,p{l,y}} por padrão ignoraria arquivos ou arquivos ocultos em diretórios ocultos. À medida que a expansão da chave se expande para vários globs, você também obteria erros (fatais com zsh ou bash -O failglob ) se esses globs não corresponderem.

Com zsh , você usa ./**/*.(c|h|p[ly])(D.) , que é um glob, e onde D inclui arquivos ocultos e . restringe-se a arquivos regulares .

Para uma solução que leva em conta a largura real dos caracteres (assumindo que todos os arquivos de texto estão codificados na codificação de caracteres do local), você pode usar:

git grep -h '' ./**/*.(c|h|p[ly])(.) | tr '\r\f' '\n\n' |
  perl -Mopen=locale -MText::Tabs -MText::CharWidth=mbswidth -lne '
    $n++ if mbswidth(expand($_)) > 80;
    END{print 0+$n}'

Observe que, pelo menos nos sistemas GNU, mbswidth() considera os caracteres de controle como tendo uma largura de -1 e 1 para expand() . Assumimos que nenhum caracter de controle diferente de CR, NL, TAB, FF é encontrado nos arquivos.

    
por 14.09.2018 / 09:48
1

Uma solução com ex (de vi ). Ainda que lento.

Como o vi é capaz de processar corretamente dados UTF-8:

Ele pode expandir tabulações para espaços, contar caracteres de controle como 1, processar \r \t \f \v corretamente e também processar a maioria dos valores UNICODE válidos . Incluindo acentos compostos (NKC) e decompostos (NKD) e caracteres de cirílico, árabe, grego, chinês e muitos outros.

$ cat script.sh
#!/bin/bash --

declare -i count=0

for i do
    # Set ex script in one variable
    a='set expandtab        "       Expand tabs to spaces
       r '"$i"'             "       Read original file
       g/^.\{,80\}$/d       "       Remove all lines shorter than the value used
       wq                   "       Quit ' 

    o=outfile; :>"$o"           # Clean output file
    ex -s "$o" <<<"$a"          # process lines in $i file
    count+=$(wc -l <"$o")       # count and accumulate number of lines.
done

echo "$count"

Chame script como:

$ script.sh     **/*.{c,h,p{l,y}}
44984
    
por 15.09.2018 / 16:23

Tags