p='[:punct:]' s='[:space:]'
sed -Ee'1!{/\n/!b' -e\} \
-e's/(\n*)(.*)/ \2 \1/' \
-e"s/is[$p]?[$s]/\n&/g" \
-e"s/([^$s])\n/\1/g;1G" \
-e:c -e"s/\ni(.* )\n{3}/u\1/" \
-e"/\n$/!s/\n//g;/\ni/G" \
-e's//i/;//tc' \
-e's/^ (.*) /\1/;P;$d;N;D'
Цей біт sedпросто несе підрахунок isподій з одного рядка в інший. Він повинен надійно обробляти стільки isес на рядок, скільки ви кидаєте на нього, і йому не потрібно буферувати старі рядки, поки це відбувається - він просто зберігає один символ нового рядка для кожного, з isяким він стикається, що не є частиною іншого слова.
Підсумок полягає в тому, що він модифікує лише третій випадок у файлі - і він проводитиме рахунки за рядок. Отже, якщо файл виглядає так:
1. is is isis
2. is does
... він надрукує ...
1. is is isis
2. us does
Спочатку він обробляє крайові корпуси, вставляючи пробіл на голову та хвіст кожного рядка. Це полегшує встановлення меж слова.
Далі він шукає дійсні ises, вставляючи \newline перед усіма подіями, isякі негайно передують нулю або одному знаку пунктуації, після якого пробіл. Він робить ще один прохід і видаляє всі \nлінії виходу, яким безпосередньо передує символ, який не знаходиться в космосі. Це залишило позаду маркерів буде відповідати is.і , isале не thisабо ?is.
Далі він збирає кожен маркер до хвоста струни - для кожного \niматчу в рядку додає \nевлайн до хвоста струни і замінює його на iабо u. Якщо є три \nлінії в рядку, зібрані в кінці рядка, тоді він використовує u - інакше i. Перший раз, коли використовується au, також є останнім - заміна заповнює нескінченний цикл, який зводиться до get line, print line, get line, print line,тощо.
Наприкінці кожного циклу спроб циклу він очищає вставлені пробіли, друкує лише до першої зустрічної нової лінії у просторі шаблону та переходить знову.
Я додаю lкоманду ook на чолі циклу, наприклад:
l; s/\ni(.* )\n{9}/u\1/...
... і подивіться, що це робить, як це працює з цим входом:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged is.
... так ось що це робить:
hai this \nis linux. \n$ #behind the scenes
hai this is linux. #actually printed
hai this \nis unix. \n\n$ #it builds the marker string
hai this is unix.
\n\n\n$ #only for lines matching the
\n\n\n$ #pattern - and not otherwise.
hai this \nis mac. \n\n\n$ #here's the match - 3 ises so far in file.
hai this us mac. #printed
hai this is unchanged is. #no look here - this line is never evaled
Має більше сенсу, можливо, з більшою кількістю isес на рядок:
nthword()( p='[:punct:]' s='[:space:]'
sed -e '1!{/\n/!b' -e\} \
-e 's/\(\n*\)\(.*\)/ \2 \1/' \
-e "s/$1[$p]\{0,1\}[$s]/\n&/g" \
-e "s/\([^$s]\)\n/\1/g;1G;:c" \
-e "${dbg+l;}s/\n$1\(.* \)\n\{$3\}/$2\1/" \
-e '/\n$/!s/\n//g;/\n'"$1/G" \
-e "s//$1/;//tc" -e 's/^ \(.*\) /\1/' \
-e 'P;$d;N;D'
)
Це практично те саме, але написане w / POSIX BRE та рудиментарна обробка аргументів.
printf 'is is. is? this is%.0s\n' {1..4} | nthword is us 12
... стає ...
is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is
... і якщо я ввімкну ${dbg}:
printf 'is is. is? this is%.0s\n' {1..4} |
dbg=1 nthword is us 12
... ми можемо спостерігати, як це повторюється ...
\nis \nis. \nis? this \nis \n$
is \nis. \nis? this \nis \n\n$
is is. \nis? this \nis \n\n\n$
is is. is? this \nis \n\n\n\n$
is is. is? this is
\nis \nis. \nis? this \nis \n\n\n\n\n$
is \nis. \nis? this \nis \n\n\n\n\n\n$
is is. \nis? this \nis \n\n\n\n\n\n\n$
is is. is? this \nis \n\n\n\n\n\n\n\n$
is is. is? this is
\nis \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n$
is \nis. \nis? this \nis \n\n\n\n\n\n\n\n\n\n$
is is. \nis? this \nis \n\n\n\n\n\n\n\n\n\n\n$
is is. is? this \nis \n\n\n\n\n\n\n\n\n\n\n\n$
is is. is? this us
is is. is? this is