Szukam sposobu na zastąpienie ciągów znaków zastępczych w pliku szablonu konkretnymi wartościami za pomocą popularnych narzędzi uniksowych (bash, sed, awk, może perl). Ważne jest, aby zastąpienie odbywało się w jednym przejściu, co oznacza, że to, co już zostało zeskanowane / wymienione, nie może być brane pod uwagę przy kolejnej wymianie. Na przykład te dwie próby kończą się niepowodzeniem:
echo "AB" | awk '{gsub("A","B");gsub("B","A");print}'
>> AA
echo "AB" | sed 's/A/B/g;s/B/A/g'
>> AA
Poprawnym wynikiem w tym przypadku jest oczywiście BA.
Ogólnie rzecz biorąc, rozwiązanie powinno być równoważne skanowaniu danych wejściowych od lewej do prawej w celu uzyskania najdłuższego dopasowania do jednego z podanych ciągów zastępczych oraz dla każdego dopasowania, wykonania zamiany i kontynuowania od tego momentu na wejściu (żaden z już odczytane dane wejściowe ani wykonane zamiany nie powinny być brane pod uwagę w przypadku dopasowań). W rzeczywistości szczegóły nie mają znaczenia, tylko to, że wyniki zamiany nigdy nie są brane pod uwagę przy kolejnej wymianie, w całości lub w części.
UWAGA Szukam tylko poprawnych ogólnych rozwiązań. Proszę nie proponować rozwiązań, które zawodzą w przypadku niektórych danych wejściowych (pliki wejściowe, wyszukiwanie i zamiana par), choć mogą się wydawać mało prawdopodobne.
tr AB BA
.Odpowiedzi:
OK, ogólne rozwiązanie. Następująca funkcja bash wymaga
2k
argumentów; każda para składa się z elementu zastępczego i zamiennika. Od Ciebie zależy, czy odpowiednio podasz ciągi znaków, aby przekazać je do funkcji. Jeśli liczba argumentów jest nieparzysta, zostanie dodany domyślny pusty argument, który skutecznie usunie wystąpienia ostatniego symbolu zastępczego.Ani symbole zastępcze, ani zamienniki nie mogą zawierać znaków NUL, ale możesz użyć standardowych
\
krajobrazów C, na przykład,\0
jeśli potrzebujeszNUL
s (a zatem musisz pisać,\\
jeśli chcesz\
).Wymaga standardowych narzędzi do budowania, które powinny być obecne w systemie podobnym do POSIX-a (lex i cc).
Zakładamy, że
\
jeśli jest to konieczne w argumentach , jest już poprzedzane znakiem ucieczki, ale musimy unikać podwójnych cudzysłowów, jeśli są obecne. Tak właśnie działa drugi argument do drugiego printf. Ponieważlex
domyślną akcją jestECHO
, nie musimy się tym martwić.Przykładowy przebieg (z czasami sceptycznymi; to tylko tani laptop na towary):
W przypadku większych danych wejściowych przydatne może być dostarczenie flagi optymalizacji
cc
, a dla obecnej zgodności Posix lepiej byłoby użyćc99
. Jeszcze bardziej ambitna implementacja może próbować buforować wygenerowane pliki wykonywalne zamiast generować je za każdym razem, ale generowanie ich nie jest drogie.Edytować
Jeśli masz tcc , możesz uniknąć kłopotów z utworzeniem katalogu tymczasowego i cieszyć się szybszym czasem kompilacji, który pomoże na wejściach normalnej wielkości:
źródło
fn() { tcc ; } <<CODE\n$(gen code)\nCODE\n
. Czy mogę jednak zapytać - to niesamowita odpowiedź i przegłosowałem ją, gdy tylko ją przeczytałem - ale nie rozumiem, co się dzieje z tablicą powłokową? Co"${@//\"/\\\"}"
to robi?Coś takiego zawsze zastępuje każde wystąpienie docelowych ciągów tylko raz, ponieważ występują one
sed
w strumieniu z jednym bitem na linię. To najszybszy sposób, w jaki mogę sobie wyobrazić, że to zrobisz. Z drugiej strony, nie piszę C. Ale to niezawodnie radzi sobie z ogranicznikami zerowymi, jeśli chcesz. Zobacz tę odpowiedź za, jak to działa. Nie ma problemów z żadnymi zawartymi specjalnymi znakami powłoki lub podobnymi - ale jest to specyficzne dla ustawień regionalnych ASCII, lub innymi słowy,od
nie będzie wypisywać znaków wielobajtowych w tym samym wierszu i wykona tylko jeden na. Jeśli jest to problem, chcesz go dodaćiconv
.źródło
sed
i zapisać do zera lub coś takiego, a następniesed
napisać ten skrypt; lub umieść go w funkcji powłoki i nadaj jej wartości po jednym kęsie w wierszu, na przykład"/$1/"
..."/$2/"
- może też napiszę te funkcje ...PLACE1
,PLACE2
iPLA
.PLA
zawsze zwycięża. OP mówi: „odpowiednik skanowania wejścia od lewej do prawej w celu uzyskania najdłuższego dopasowania do jednego z podanych ciągów zastępczych” (podkreślenie dodane)perl
Rozwiązaniem. Nawet jeśli niektórzy stwierdzili, że nie jest to możliwe, znalazłem jeden, ale generalnie proste dopasowanie i zamiana nie jest możliwe, a nawet pogarsza się z powodu wycofania NFA, wynik może być nieoczekiwany.Ogólnie rzecz biorąc, i trzeba to powiedzieć, problem wywołuje różne wyniki, które zależą od kolejności i długości zastępczych krotek. to znaczy:
a dane wejściowe
AAA
skutkują wBBB
lubCCB
.Oto kod:
Checkerbunny:
źródło