Załóżmy, że jest jakiś tekst z pliku:
(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)
Chcę dodać 11 do każdego numeru, a następnie "
w każdym wierszu, jeśli taki jest, tj
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)
Oto moje rozwiązanie, używając GNU AWK i regex:
awk -F'#' 'NF>1{gsub(/"(\d+)\""/, "\1+11\"")}'
to znaczy, chcę wymienić (\d+)\"
z \1+10\"
, gdzie \1
jest grupa reprezentująca (\d+)
. Ale to nie działa. Jak mogę to zrobić?
Jeśli gawk nie jest najlepszym rozwiązaniem, czego jeszcze można użyć?
Odpowiedzi:
Spróbuj tego (gawk jest potrzebny).
Przetestuj na swoim przykładzie:
Zauważ, że to polecenie nie będzie działać, jeśli dwie liczby (np. 1 ”i„ # 1 ”) są różne. Lub w tym samym wierszu jest więcej liczb z tym wzorem (np. 23„ ... 32 ”...” # 123 ") w jednym wierszu.
AKTUALIZACJA
Ponieważ @Tim (OP) powiedział, że liczba, po której następuje ta
"
sama linia, może być inna, wprowadziłem pewne zmiany w moim poprzednim rozwiązaniu i sprawiłem , że działało w twoim nowym przykładzie.BTW, z przykładu uważam, że może to być tabela struktury treści, więc nie rozumiem, jak te dwie liczby mogą się różnić. Pierwszy to wydrukowany numer strony, a drugi z # to indeks strony. Czy mam rację?
W każdym razie najlepiej znasz swoje wymagania. Teraz nowe rozwiązanie, wciąż z gawk (dzielę polecenie na linie, aby ułatwić czytanie):
przetestuj na nowym przykładzie:
EDIT2 na podstawie komentarza @Tim
Masz rację dla separatora zarówno w części wejściowej, jak i wyjściowej. Zdefiniował separator jako:
Istnieją dwa podwójne cudzysłowy, ponieważ łatwiej jest złapać dwie pożądane liczby (na podstawie przykładowego wejścia).
Dokładnie!
To jest z http://www.gnu.org/s/gawk/manual/html_node/String-Functions.html . możesz przeczytać, aby uzyskać szczegółowe informacje na temat korzystania z gensub.
źródło
awk -F'#'
wydaje się, że chcesz wprowadzić zmiany tylko po „#”?FS=OFS="\" \"#"
oznacza, że separatorem pola zarówno na wejściu, jak i na wyjściu jest podwójny cudzysłów, spacja, podwójny cudzysłów i #? po co podawać podwójną wycenę dwa razy? (2) w/.* ([0-9]+)$/
,$
oznacza koniec łańcucha? (3) w trzecim argumencie gensub () jaka jest różnica między"g"
i"G"
?W przeciwieństwie do niemal każdego narzędzia, które zapewnia podstawienia wyrażeń regularnych, awk nie zezwala na odwołania wsteczne, takie jak
\1
w tekście zastępczym. GNU awk daje dostęp do grup dobranych w przypadku korzystania zmatch
funkcji , ale nie z~
lubsub
lubgsub
.Zauważ też, że nawet jeśli
\1
byłby obsługiwany, twój fragment kodu dołączałby ciąg+11
, nie wykonując obliczeń numerycznych. Ponadto wyrażenie regularne nie jest w porządku, dopasowujesz rzeczy takie jak"42""
i nie"#42"
.Oto rozwiązanie awk (ostrzeżenie, niesprawdzone). Wykonuje tylko jedną zamianę na linię.
W Perlu byłoby łatwiej.
źródło
awk
może to zrobić, ale nie jest to bezpośrednie, nawet przy użyciu odsyłania wstecznego.GNU awk ma (częściowe) odsyłanie zwrotne, w postaci gensub .
Instancje
123"
są tymczasowo pakowane\x01
i\x02
oznaczane jako niezmodyfikowane (npsub()
. CoLub możesz po prostu przejść przez pętlę zmieniając kandydatów w trakcie podróży, w którym to przypadku odsyłanie zwrotne i „nawiasy” nie są potrzebne; ale konieczne jest śledzenie indeksu postaci.
Oto inny sposób: użycie
gensub
i tablicasplit
oraz\x01
jako separator pola (do podziału ) .. \ x02 oznacza element tablicy jako kandydata do dodania arytmetycznego.źródło
"\x01\\1\"\x02"
oznacza? Nadal nie rozumiem\x01
i\x02
. (2) na ile różni się zwrot$0
przezgensub
i$0
od ostatniego argumentugensub
?\x01
i\x02
są używane jako znaczniki podstawienia. Wartości te są bardzo mało prawdopodobne, aby być w każdym normalnym pliku tekstowym, więc są one w równym stopniu „bardzo” bezpieczne w użyciu (tzn. Nie wystąpi konflikt z tych istniejących wcześniej) .. Są etykiety tylko tymczasowe .. Re$0=gensub(... $0)
.. zobaczyć link Funkcje manipulacji ciągami , ale w skrócie: To (gensub) zwraca zmodyfikowany ciąg jako wynik funkcji, a pierwotny ciąg docelowy nie jest zmieniany. ... To$0=
po prostu modyfikuje pierwotny cel.Ponieważ rozwiązania w (g) awk wydają się dość skomplikowane, chciałem dodać alternatywne rozwiązanie w Perlu:
Wyjaśnienie:
-w
włącza ostrzeżenia (które ostrzegają o możliwych niepożądanych efektach).-p
zakłada pętlę wokół kodu, który działa podobnie do sed lub awk, oszczędzając każdy wiersz wejścia automatycznie w zmiennej domyślnej$_
.-e
informuje perla, że kod programu podąża za wierszem poleceń, a nie w pliku skryptu.s/.../.../
)$_
, w którym ciąg cyfr, po którym następuje a"
, zostanie zastąpiony przez ciąg interpretowany jako liczba w dodatku, plus 11.(?=pattern)
wyszukuje"
bez zabraniem go na mecz, więc nie trzeba powtarzać go w wymianie. Zmienna MATCH$&
w zastępstwie będzie wówczas zawierać tylko liczbę./e
Modyfikator do regex mówiperl
do „execute” zastąpienia jako kod zamiast brać go jako ciąg znaków./g
Modyfikator powoduje zastąpienie „globalny”, powtarzając go na każdym meczu w wierszu.Zmienna MATCH
$&
będzie niestety szkodliwa dla wydajności kodu w wersjach Perla przed 5.20. Szybsze (i niewiele bardziej skomplikowane) rozwiązanie użyłoby$1
zamiast tego grupowania i odwołań wstecznych :A jeśli stwierdzenie dotyczące przyszłości wydaje się zbyt mylące, można również wyraźnie zastąpić znak cudzysłowu:
źródło