Jak policzyć liczbę znaków w linii, z wyjątkiem określonego znaku?

9

To jest plik części

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

W każdym wierszu chcę policzyć całkowitą liczbę wszystkich znaków, które nie są „N”

moje pragnienie wyjściowe

1
1
1
0
1
2
2
Anna1364
źródło
Służy seddo zastępowania rzeczy, na których ci nie zależy, i awkdo zliczenia pozostałej długoścised 's/N//g ; s/\s//g' file | awk '{ print length($0); }'
Rolf

Odpowiedzi:

13

Rozwiązanie GNU awk :

awk -v FPAT='[^N[:space:]]' '{ print NF }' file
  • FPAT='[^N[:space:]]'- wzorzec definiujący wartość pola (dowolny znak z wyjątkiem Nznaku i białych znaków)

Oczekiwana wydajność:

1
1
1
0
1
2
2
Roman Perekhrest
źródło
9
awk '{ gsub("[ N]",""); print length() }'
Hauke ​​Laging
źródło
można również użyćawk '{print gsub(/[^ N]/,"")}'
Sundeep
7

zakładając, że liczba jest potrzebna dla każdej linii innej niż znak spacji i N

$ perl -lne 'print tr/N //c' ip.txt 
1
1
1
0
1
2
2
  • wartość zwracana trto ile znaków zostało zastąpionych
  • c w celu uzupełnienia zestawu podanych znaków
  • Zwróć uwagę na użycie -lopcji, usuwa znak nowej linii z linii wprowadzania, aby uniknąć błędu off-by-one, a także dodaje znak nowej linii do instrukcji print


Bardziej ogólne rozwiązanie

perl -lane 'print scalar grep {$_ ne "N"} @F' ip.txt 
  • -aopcja automatycznego podziału linii wejściowej na białe spacje, zapisana w @Ftablicy
  • grep {$_ ne "N"} @Fzwraca tablicę wszystkich elementów, w @Fktórych nie pasuje ciągN
    • odpowiednikiem wyrażenia regularnego byłoby grep {!/^N$/} @F
  • użycie scalarda da liczbę elementów tablicy
Sundeep
źródło
6

Alternatywne rozwiązanie awk :

awk '{ print gsub(/[^N[:space:]]/,"") }' file
  • gsub(...)- gsub()Funkcja zwraca liczbę dokonanych podstawień.

Wyjście:

1
1
1
0
1
2
2
Roman Perekhrest
źródło
6

Inne awkpodejście (zwróci -1 dla pustych linii).

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

Lub w postaci złożonej zwróci -1 w pustych wierszach, 0 tylko w wierszach z białymi spacjami (tabulatory / spacje).

awk -F'[^N \t]+' '$0=NF-1""' infile
αғsнιη
źródło
wypisze -1dla pustych linii ... ale wtedy może być pożądane rozróżnienie linii złożonej tylko z N / spacji vs pustej linii ...
Sundeep
1
@ Sundeep Tak, to prawda. zobacz także moją aktualizację, w której wiersze zawierały tylko tabulatory lub spacje, które mają być oznaczone jako 0
αғsнιη
5
  1. tri skrypt powłoki POSIX :

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

    while read x ; do x="${x//[ N]}" ; echo ${#x} ; done < file
    
agc
źródło
1
można użyć, awk '{print length()}'aby uniknąć wolniejszego zapętlania powłoki ... ale wtedy można to wszystko zrobić z samym awk ...
Sundeep
@ Sundeep, to prawda ( jeśli oba są uruchamiane w tym samym czasie), że awkzapętlenie jest szybsze niż zapętlenie powłoki. Ale powłoka jest zawsze w pamięci i awkmoże nie być - gdy awknie jest już załadowana lub zamieniona, narzut związany z jej ładowaniem ( stracony czas ) może być większy niż korzyść z działania awk- szczególnie na małym pętla. W takich przypadkach ( tj. W tym przypadku) awkmoże być wolniejszy .
agc
cóż, na pewno nie martwię się czasem na drobne rzeczy ... patrz unix.stackexchange.com/questions/169716/…
Niedziela
1
@Sundeep, mam zrobić martwić. Jakiś czas temu używałem dyskietek Linuxowych opartych na dyskietkach , które mogłyby uciekać z dyskietki, w kilka megabajtów pamięci RAM. Niepotrzebne użycie awkw skrypcie powłoki może spowodować, że taki system będzie się czołgał na czworakach. Ogólnie: to samo opóźnienie opóźnień dotyczy systemów z ograniczonym oprogramowaniem układowym lub dowolnego systemu o dużym obciążeniu.
agc
1

Krótka kombinacja tri awk:

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

To usuwa wszystkie spacje i Ns z pliku wejściowego i awkpo prostu drukuje długość każdej linii.

Kusalananda
źródło
0

Innym łatwym sposobem jest zrobienie tego w Pythonie, który jest wstępnie zainstalowany w większości środowisk unixowych. Upuść następujący kod w pliku .py:

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

A następnie wykonaj:

python file.py

Z twojego terminala. Powyższe powoduje:

  • dla każdej linii w pliku o nazwie „geno”
  • ustaw licznik na 0 i zwiększaj go za każdym razem, gdy znajdziemy wartość! = 'N'
  • po osiągnięciu końca bieżącej linii wydrukuj licznik i przejdź do następnej linii
Grajdeanu Alex.
źródło