Zählen Sie Zeilen, die breiter als 80 Spalten sind, und berücksichtigen Sie dabei die Registerkarten korrekt

7

Um Zeilen mit mehr als 80 Spalten zu zählen, verwende ich derzeit diesen Befehl:

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

Leider verwendet das Repo Tabulatoren zum Einrücken, sodass das grepMuster ungenau ist. Gibt es überhaupt eine Möglichkeit, die regexRegisterkarten mit der Standardbreite von 8 Zeichen zu versehen, wie wc -L?

Für die Zwecke dieser Frage können wir davon ausgehen, dass die Mitwirkenden diszipliniert genug waren, um konsequent einzurücken, oder dass sie git commitanstelle von Disziplin Haken haben .

Aus Gründen der Leistung würde ich eine Lösung bevorzugen, die innerhalb git-grep(1)oder möglicherweise in einem anderen grepTool funktioniert , ohne Dateien vorzuverarbeiten .

phg
quelle

Antworten:

8

Wenn wir gemäß Ihrem Kommentar davon ausgehen können, dass Tabulatorzeichen nur am Zeilenanfang angezeigt werden, können wir Alternativen zu mindestens 80 Zeichen zählen.

  • Keine Tabulatoren, mindestens 81 Zeichen
  • Eine Registerkarte mit mindestens 73 Zeichen
  • Zwei Registerkarten, mindestens 65 Zeichen
  • Usw.

Das resultierende Durcheinander ist wie folgt: Ihre awkAussage summiert die einzelnen Zeilenzahlen, um eine Gesamtsumme zu erhalten

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) }'
Roaima
quelle
Beachten Sie, dass git grep -P(zumindest mit meiner 2.18.0-Version unter Debian hier) nicht mit Mehrbyte-Zeichen funktioniert. Beispielsweise wird davon ausgegangen, dass ©(in Quelldateien üblich) 2 Zeichen anstelle von einem Zeichen sind, wenn es in UTF-8 codiert ist. Es ist in Ordnung mit -E. Sie können es in UTF-8-Gebietsschemas git grep -hcP '(*UTF8)...'
Stéphane Chazelas
@ StéphaneChazelas, wenn ich zu -Edann wechsle, \twird nicht erkannt. Ich nehme an, die schnelle Lösung besteht darin, eine mit Ansi C zitierte Zeichenfolge $'...'anstelle einer mit einfachen Anführungszeichen zu verwenden '...'.
Roaima
12

Verarbeiten Sie die Dateien vorab, indem Sie sie durchleiten expand. Das expandDienstprogramm erweitert die Registerkarten entsprechend (unter Verwendung der Standard-Tabulatoren bei jedem 8. Zeichen).

find . -type f \( -name '*.[ch]' -o -name '*.p[ly]' \) -exec expand {} + |
awk 'length > 80 { n++ } END { print n }'
Kusalananda
quelle
10

GNU wc -Lbehandelt TABs nicht als 8 Zeichen, sondern TABs so, wie sie in einem Terminal mit TAB-Stopps alle 8 Spalten angezeigt werden. Die "Breite" liegt also zwischen 1 und 8 Zeichen, je nachdem, wo sie sich in der Zeile befinden . wc -LBerücksichtigt auch die Anzeigebreite anderer Zeichen (unabhängig davon, ob sie 0, 1 oder 2 Spalten breit sind) und verarbeitet \fund \r"korrekt".

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

Hier können Sie expanddiese TABs verwenden (wobei standardmäßig auch alle 8 Spalten Tabulatoren vorausgesetzt werden, obwohl Sie sie mit Optionen ändern können), um diese TABs auf Leerzeichen zu erweitern:

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

(Konvertieren der CRs (die beim Senden an ein Terminal den Cursor zurück zum Zeilenanfang bewegen) und der FFs (die von einigen Anzeigegeräten als Seitenumbruch verstanden werden) in LF, um das gleiche Verhalten wie zu erhalten wc -L, die anderen jedoch zu ignorieren was wir sowieso nicht sagen können, welchen Einfluss sie auf die Anzeigebreite haben werden).

Dies gilt für TABs, jedoch nicht für Zeichen mit einfacher oder doppelter Breite. Beachten Sie, dass die GNU-Implementierung von expandderzeit TABs nicht richtig erweitert, wenn Mehrbyte-Zeichen vorhanden sind (geschweige denn Null- oder Doppelbreitenzeichen).

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

Beachten Sie auch, dass ./**/*.{c,h,p{l,y}}standardmäßig versteckte Dateien oder Dateien in versteckten Verzeichnissen übersprungen werden. Wenn die Klammererweiterung auf mehrere Globs erweitert wird, werden auch Fehler (schwerwiegend mit zshoder bash -O failglob) angezeigt, wenn einer dieser Globs nicht übereinstimmt.

Mit würden zshSie verwenden, ./**/*.(c|h|p[ly])(D.)welches ein Glob ist und wo Dversteckte Dateien enthalten und .auf reguläre Dateien beschränkt sind.

Für eine Lösung, die die tatsächliche Breite der Zeichen berücksichtigt (vorausgesetzt, alle Textdateien sind in der Zeichencodierung des Gebietsschemas codiert), können Sie Folgendes verwenden:

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}'

Beachten Sie, dass zumindest auf GNU-Systemen mbswidth()Steuerzeichen mit einer Breite von -1und 1 für betrachtet werden expand(). Wir gehen davon aus, dass in den Dateien kein anderes Steuerzeichen als CR, NL, TAB, FF gefunden wird.

Stéphane Chazelas
quelle
"GNU wc -L behandelt TABs nicht als 8 Zeichen, sondern TABs so, wie sie in einem Terminal mit TAB-Stopps alle 8 Spalten angezeigt würden." Sie haben natürlich Recht, aber wenn Tabulatoren nur zum Einrücken verwendet werden, läuft das auf dasselbe hinaus.
Phg
1
Für die Zwecke dieser Frage können wir davon ausgehen, dass die Mitwirkenden diszipliniert genug waren, um konsequent einzurücken (oder dass sie anstelle von Disziplin Git-Commit-Hooks haben).
Phg
1
@phg, wenn man sich den Linux-Kernel-Quellbaum ansieht (eine alte Kasse von Mai, über die ich gelogen habe), findet @ roaimas Ansatz 32408 zu viele Zeilen. Nicht so sehr über das Einrücken gemischter Tabulatoren + SPCs, sondern weil Tabulatoren auch für Spaltenausrichtungen für tabellenartige Sequenzen #define symbol valueoder Deklarationen verwendet werden.
Stéphane Chazelas
1
Interessantes Ergebnis, aber wir haben es hier nicht mit dem Kernelbaum zu tun.
Phg
1
Die Registerkarte @jamesqf besteht aus 8 Zeichen. Wenn Sie das ändern möchten, ist es Ihr Problem. Fast alle Dienstprogramme, die Tab als Tab-Aktion verstehen, setzen Tabulatorstopps mit 8 Zeichen voraus. Persönlich verwende ich Softtabs mit 2 oder 4 Zeicheneinzügen. Wenn Einrückungen bis zu 8 bilden, ersetzt mein Editor sie durch einen Tabulator (es sei denn, ich schreibe Python).
Roaima
1

Eine Lösung mit ex (aus vi ). Wenn auch langsam.

Da vi UTF-8-Daten korrekt verarbeiten kann:

Es könnte Tabulatoren zu Leerzeichen erweitern, Steuerzeichen als 1 zählen, \r \t \f \vkorrekt verarbeiten und auch die meisten gültigen UNICODE-Werte verarbeiten. Einschließlich komponierter (NKC) und zerlegter (NKD) Akzente sowie Zeichen aus Kyrillisch, Arabisch, Griechisch, Chinesisch und vielen anderen.

$ 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"

Rufen Sie das Skript auf als:

$ script.sh     **/*.{c,h,p{l,y}}
44984
Isaac
quelle