Policz linie między literami „X”

13

Chcę policzyć linie między znakami „X”. To tylko przykład; Muszę zastosować kod do złożonego wyniku biologicznego. Będę wdzięczny, jeśli można zasugerować jakieś polecenie, najlepiej przy użyciu awk, greplub sedjak jestem zaznajomiony z tymi.

Przykład:

X
Y
Y
Y
X
Y
Y
Y
Y
X
Y
X

Pożądane wyjście:

3
4
1
Rhea
źródło
2
Możesz być zainteresowany Bioinformatyką, jeśli będziesz pracować w tej dziedzinie.
terdon

Odpowiedzi:

13

Z awk:

$ awk '!/X/{count++}/X/{print count; count = 0}' input

3
4
1

Zwiększ liczbę dla każdej linii niezawierającej X; wydrukuj i zresetuj liczbę wierszy zawierających X.

muru
źródło
2
Gdyby pierwsza linia nie była X, pierwsza liczba linii byłaby nadal liczona i wysyłana za pomocą tego rozwiązania, aż do Xdopasowania pierwszej linii z . EX (Nie można dodawać nowych wierszy w komentarzach, ale należy wziąć pod uwagę, że między każdym znakiem jest nowy wiersz; P): Y X Y Y X Y Y Ywyświetli:1 2
Dan
1
@muru to nie zadziała, jeśli na końcu nie będzie X (trzeba dodać END{if (count)print count}), a tworzenie pustej linii, w której X był na początku, aby uniknąć dodania /X/&&countwarunku również
αғsнιη
1
Heh Jeden komentarz narzeka, że ​​wiodących Ynie należy liczyć, ponieważ nie są dokładnie między dwoma X; drugi narzeka, że ​​końcowe Ys nie są liczone, ponieważ nie są dokładnie między dwoma Xs. W razie potrzeby poczekam na wyjaśnienie PO; Nie mam nic przeciwko tej odpowiedzi do chwili obecnej.
muru
12
$ awk '/X/ && prev{print NR-prev-1} /X/{prev=NR}' file
3
4
1

Jak to działa:

Awk domyślnie czyta pliki wejściowe linia po linii.

  • /X/ && prev{print NR-prev-1}

    Dla każdego wiersza, który zawiera Xi jeśli wcześniej przypisaliśmy wartość prev, wydrukuj numer bieżącego wiersza NR, minus prevminus jeden.

  • /X/{prev=NR}

    Dla każdego wiersza zawierającego Xustawić zmienną prevdo bieżącego numeru linii, NR.

John1024
źródło
4
Ej, miło. Nadużywanie NRdaje mi pomysł:awk '/X/{print NR - 1; NR = 0}' foo
muru,
Dziękuję, daje mi dokładne informacje. co jest wymagane.
Rhea,
Muro: Ładne i trudne. Z wyjątkiem drukowania jednej wartości za dużo, działa dla mnie pod gawk i mawk. Jestem ciekawy, czy takie zachowanie jest gwarantowane. @EdMorton?
John1024
3
@ rhea O ile pierwsza linia nie jest zawsze X, istnieje niewielka różnica w wynikach między 2 odpowiedziami, jak wyjaśniłem w komentarzu pod odpowiedzią Muru.
Dan
1
@ John1024 thankyou! Mam nadzieję, że to mi pomoże.
Rhea
6

Kolejne proste awkpodejście, które działa na przykładowych danych OP i jeśli Xnie było w pierwszym, a nawet w ostatnich lub powtórzonych Xs.

awk -v RS='X' 'NF{print NF}' infile

Powyższe jest poprawne, gdy w każdym wierszu znajduje się tylko jedno pole z domyślnym FS dowolnymi białymi spacjami , w przeciwnym razie poniżej poprawiono ogólny przypadek liczenia linii . Można wprowadzać swoje PATTERN w miejsce X tam.

awk -F'\n' -v RS='X' 'NF>2{print NF-2}'

Przykładowe dane wejściowe:

X
Y YYY Y
YY
YY Y YY YY Y Y
X
Y Y Y
X
Y
Y
X
X

Dane wyjściowe to:

3
1
2
αғsнιη
źródło
1

Większość odpowiedzi tutaj odpowiada zawartości wiersza, który ma być policzony przy użyciu wyrażeń regularnych osadzonych w programie Awk. Jeśli chcesz dopasować wiersze do treści, które mogą zawierać znaki specjalne (do Awk lub wyrażeń regularnych), lepiej byłoby faktycznie porównać ciągi znaków dla równości. Dlatego proponuję następujący skrypt Awk jako wariant odpowiedzi muru :

BEGIN {
    count = 0;
}

{
    if ($0 == needle) {
        if (count) {
            print count;
            count = 0;
        }
    } else {
        count++;
    }
}

Zapisz go jako plik tekstowy count-rows.awki wywołaj go w następujący sposób:

awk -f count-rows.awk -v needle=X input

Możesz dostosować wartość needledo swoich upodobań. Zaletą tej metody jest to, że można wywoływać program ze skryptu powłoki o dowolnej wartości needlebez uciekania się przed problemami:

awk -f count-rows.awk -v needle="$needle" input
David Foerster
źródło