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
Спочатку він обробляє крайові корпуси, вставляючи пробіл на голову та хвіст кожного рядка. Це полегшує встановлення меж слова.
Далі він шукає дійсні is
es, вставляючи \n
ewline перед усіма подіями, 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