Wie zähle ich die Anzahl der Zeichen in einer Zeile mit Ausnahme eines bestimmten Zeichens?

9

Dies ist eine Teiledatei

N W N N N N N N N N N
N C N N N N N N N N N
N A N N N N N N N N N
N N N N N N N N N N N
N G N N N N N N N N N
N C N N N C N N N N N
N C C N N N N N N N N

In jeder Zeile möchte ich die Gesamtzahl aller Zeichen zählen, die nicht "N" sind.

meine Wunschausgabe

1
1
1
0
1
2
2
Anna1364
quelle
Verwenden Sie sed, um Dinge zu ersetzen, die Sie nicht interessieren, und awkum die verbleibende Länge zu zählensed 's/N//g ; s/\s//g' file | awk '{ print length($0); }'
Rolf

Antworten:

13

GNU awk Lösung:

awk -v FPAT='[^N[:space:]]' '{ print NF }' file
  • FPAT='[^N[:space:]]'- das Muster, das einen Feldwert definiert (jedes Zeichen außer Zeichen Nund Leerzeichen)

Die erwartete Ausgabe:

1
1
1
0
1
2
2
RomanPerekhrest
quelle
9
awk '{ gsub("[ N]",""); print length() }'
Hauke ​​Laging
quelle
kann auch verwendenawk '{print gsub(/[^ N]/,"")}'
Sundeep
7

Angenommen, die Anzahl wird für jede andere Zeile als das Leerzeichen und benötigt N

$ perl -lne 'print tr/N //c' ip.txt 
1
1
1
0
1
2
2
  • Der Rückgabewert von trgibt an, wie viele Zeichen ersetzt wurden
  • c um den angegebenen Zeichensatz zu ergänzen
  • Beachten Sie die Verwendung der -lOption, entfernen Sie das Zeilenumbruchzeichen von der Eingabezeile, um Fehler nacheinander zu vermeiden, und fügen Sie das Zeilenumbruchzeichen für die Druckanweisung hinzu


Eine allgemeinere Lösung

perl -lane 'print scalar grep {$_ ne "N"} @F' ip.txt 
  • -aOption zum automatischen Teilen der Eingabezeile in Leerzeichen, die im @FArray gespeichert sind
  • grep {$_ ne "N"} @FGibt ein Array aller Elemente zurück, in @Fdenen die Zeichenfolge nicht übereinstimmtN
    • Regex-Äquivalent wäre grep {!/^N$/} @F
  • Die Verwendung von scalargibt die Anzahl der Elemente des Arrays an
Sundeep
quelle
6

Alternative awk Lösung:

awk '{ print gsub(/[^N[:space:]]/,"") }' file
  • gsub(...)- Die gsub()Funktion gibt die Anzahl der vorgenommenen Ersetzungen zurück.

Die Ausgabe:

1
1
1
0
1
2
2
RomanPerekhrest
quelle
6

Ein anderer awkAnsatz (gibt -1 für leere Zeilen zurück).

awk -F'[^N ]' '$0=NF-1""' infile

In komplexen Fällen wird -1 in leeren Zeilen und 0 in Leerzeichen (Tabulatoren / Leerzeichen) zurückgegeben.

awk -F'[^N \t]+' '$0=NF-1""' infile
αғsнιη
quelle
wird -1für leere Zeilen gedruckt ... aber dann könnte es wünschenswert sein, eine Zeile, die nur aus N / Leerzeichen besteht, von einer leeren Zeile zu unterscheiden ...
Sundeep
1
@Sundeep Ja, das stimmt. siehe auch mein Update, wo Zeilen nur Tabulatoren oder Leerzeichen enthielten, um als 0
αғsнιη
5
  1. trund POSIX- Shell-Skript:

    tr -d 'N ' < file | while read x ; do echo ${#x} ; done
    
  2. bash, kshUnd zsh:

    while read x ; do x="${x//[ N]}" ; echo ${#x} ; done < file
    
agc
quelle
1
kann verwendet werden awk '{print length()}', um die langsamere Shell-Schleife zu vermeiden .. aber dann könnte man alles mit awk selbst tun ...
Sundeep
@Sundeep, Es ist wahr, ( wenn beide zur gleichen Zeit gestartet werden), dass awkLooping ist schneller als Shell - Looping. Die Shell befindet sich jedoch immer im Speicher und ist awkmöglicherweise nicht - wenn sie awknoch nicht geladen oder ausgelagert ist - der Aufwand für das Laden ( die verlorene Zeit ) größer als der Vorteil des Laufens awk- insbesondere bei kleinen Schleife. In solchen Fällen ( dh in diesem Fall) awkkann es langsamer sein .
Agc
Nun,
Sundeep
1
@Sundeep, ich mache mir Sorgen. Vor einiger Zeit habe ich floppy-basierte Linux-Distributionen verwendet , die von einer Diskette in ein paar Megabyte RAM laufen könnten. Die unnötige Verwendung awkin einem Shell-Skript könnte dazu führen, dass ein solches System auf allen Vieren crawlt. Im Allgemeinen gilt der gleiche Latenzwiderstand für Systeme mit eingeschränkter Firmware oder für Systeme unter hoher Last.
Agc
1

Eine kurze Kombination von tr und awk:

$ tr -d ' N' <file.in | awk '{ print length }'
1
1
1
0
1
2
2

Dadurch werden alle Leerzeichen und Ns aus der Eingabedatei gelöscht und awknur die Länge jeder Zeile gedruckt.

Kusalananda
quelle
0

Eine andere einfache Möglichkeit besteht darin, dies in Python zu tun, das in den meisten Unix-Umgebungen vorinstalliert ist. Fügen Sie den folgenden Code in eine .py-Datei ein:

with open('geno') as f:
    for line in f:
        count = 0
        for word in line.split():
            if word != 'N':
                count += 1
        print(count)

Und dann mache:

python file.py

Von Ihrem Terminal. Was das Obige tut, ist:

  • für jede Zeile in einer Datei mit dem Namen "geno"
  • Setzen Sie einen Zähler auf 0 und erhöhen Sie ihn jedes Mal, wenn wir einen Wert finden! = 'N'
  • Wenn das Ende der aktuellen Zeile erreicht ist, drucken Sie den Zähler und fahren Sie mit der nächsten Zeile fort
Grajdeanu Alex.
quelle