Załóżmy, że mam dane dwóch linii o tej samej długości
abcdb#lae#blabl#a
abc~bola~xblabl~a
Muszę usunąć #
znak w pierwszym wierszu (może być jeden lub wiele # w pierwszym wierszu), a także znak w tym samym miejscu w następnym wierszu, aby dane stały się
abcdblaeblabla
abc~bla~blabla
Próbowałem, sed '/#/{n;s/~//g}'
ale usuwa więcej znaków, niż chcę.
text-processing
awk
sed
Jason Qin
źródło
źródło
Odpowiedzi:
awk
Metody te powtarzają się dla każdej pary linii (1 i 2; 3 i 4; itd.), Pracując dla tylu
#
znaków, ile jest w pierwszym wierszu każdej pary i zakładając, że dwie linie każdej pary mają tę samą długość.Kompatybilny z GNU awk (Linux) i BSD awk (Mac).
Za pomocą podciągów:
Ten sam kod, sformatowany dla węższych ekranów:
a=$0
Zapisz kopię pierwszego wiersza.
gsub(/#/,"",$0) ; print $0
Usuń wszystko
#
z pierwszego wiersza (nie z kopii), a następnie wydrukuj zmodyfikowany pierwszy wiersz.getline
Przejdź do następnej linii.
for (n=1;n<=length(a);n++)
Przechodź przez każdy znak kopii pierwszego wiersza.
if ( substr(a,n,1) != "#" )
Jeśli ten jednoznakowy podciąg nie jest
#
…printf "%s",substr($0,n,1)
… Następnie wydrukuj znak z odpowiedniej pozycji w drugim wierszu.
printf "%s",RS
Zakończ drugą linię znakiem nowej linii.
Korzystanie z tablic:
Przeformatowany dla węższych ekranów:
c=d=""
Zainicjuj dwa puste ciągi. Będą to zmodyfikowane wersje dwóch linii wejściowych. Ten krok jest konieczny, jeśli są więcej niż dwa wiersze wprowadzania.
elements=split($0,a,"")
Przekształć pierwszy wiersz danych wejściowych w tablicę, z jednym znakiem na element tablicy. Przechowuj liczbę elementów tablicy jako zmienną
elements
.getline
Przejdź do następnej linii.
split($0,b,"")
Przekształć drugi wiersz danych wejściowych w tablicę, z jednym znakiem na element tablicy.
for (n=1;n<=elements;n++)
Przejdź przez każdy element tablicy pierwszego wiersza.
if (a[n]!="#")
Jeśli ten element tablicy jednoznakowej nie jest
#
…{ c = c a[n] ; d = d b[n] }
… Następnie, dla każdej z dwóch linii, zachowaj znak z pozycji
n
.print c ; print d
Wydrukuj nowe wersje dwóch linii.
Uwaga: Wersja awk dla komputerów Mac (BSD) nie obsługuje automatycznie elementów tablicy w kolejności numerycznej. To początkowo dało mi zaskakujące wyniki.
Elementy są nadal ponumerowane
1,2,3,...
w momencie tworzeniasplit
, podobnie jak w GNU awk, ale awk BSD niekoniecznie widzi je w tej kolejności podczas używaniafor (n in array)
. W ten sposób dostaniesz bełkot.Aby obejść ten problem, możesz zapisać długość tablicy (liczbę elementów) podczas tworzenia tablicy - np.
elements=split($0,a,"")
- a następnie iterować elementy za pomocąfor (n=1;n<=elements;n++)
, tak jak to zrobiłem tutaj.Przykładowe wejście (
file.txt
):Przykładowe dane wyjściowe:
źródło
Możesz to zrobić za pomocą sed w następujący sposób. Umieść dwa znaczniki na początku dwóch linii, po umieszczeniu obu w przestrzeni wzorów.
Następnie zacznij przesuwać je w prawo po jednej postaci. Podczas tego ruchu zwróć uwagę na to, co leży bezpośrednio na prawo od markerów i podejmij odpowiednie działania.
Zatrzymaj się, gdy znacznik dotrze do końca obszaru wzoru. Teraz zdejmij znaczniki, gdy ich praca zostanie wykonana, a to, czego chcesz, to czego chcesz. Uwaga: znacznikiem jest \ n
Korzystanie z Perla jest rozwiązywane według następujących zasad:
Pracujący:
Pokazana jest inna metoda, tym razem wykorzystująca tablice:
Pracujący:
Metoda wyrażeń regularnych:
Opis:
° dołącz kolejną linię do prądu, o ile nie jest to ostatnia linia.
° Zapisz pozycje znaków skrótu w pierwszym wierszu za pomocą pętli while.
° Następnie usuń znak krzyżyka z pierwotnego wiersza i znak z odpowiedniej pozycji w następnym wierszu.
° Po zakończeniu pętli while opcja - p automatycznie wydrukuje $ _ na standardowe wyjście.
Metoda z operacjami zwykłego łańcucha:
Obejmuje to użycie wbudowanego indeksu do sprawdzenia pozycji skrótu, a następnie użycie tego w wbudowanym substracie dwa razy ... w pierwszej i następnej linii.
źródło
Jest to dość łatwe
awk
. Kiedy zobaczysz a#
, określ, gdzie jest w linii. Następnie dla tej linii i wszystkich kolejnych linii wytnij tę pozycję znaku z linii.źródło
źródło
Z gnu awk za pomocą gensub
Wyjaśnić :
/ # /: dla każdej linii z #
a = 0 USD: zapisz wiersz w
b = długość (): pobierz długość w b
getline: pobierz następną linię
0 USD = RS 0 USD: dodaj poprzednią linię zapisaną na początku bufora 0 USD, a następnie RS separator rekordów
Teraz 0 $ zawiera 2 linie
while ($ 0! = a): podczas gdy linia przechowywana w a różni się od bufora 0 $
a = 0 USD: pobierz bufor 0 USD w
0 $ = gensub ("([^ #] *) # (. {" B - "}).", "\\ 1 \\ 2", 1): usuń pierwszy # w $ 0 i odpowiedni znak w druga linia
W tym samym czasie zmniejszenie (b--) długości pierwszego wiersza o 1, ponieważ 1 # został usunięty
1: gdy nie ma już # w pierwszym wierszu, wydrukuj 0 USD
źródło