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
es на строку, сколько вы набрасываете на него, и ему не нужно буферизовать старые строки, пока он это делает - он просто сохраняет один символ новой строки для каждого is
, с чем встречается, который не является частью другого слова.
В результате он будет изменять только третье вхождение в файле - и он будет иметь число в строке. Так что если файл выглядит так:
1. is is isis
2. is does
... это будет печатать ...
1. is is isis
2. us does
Сначала он обрабатывает края, вставляя пробел в начало и конец каждой строки. Это немного облегчает определение границ слов.
Затем он ищет действительные значения is
, вставляя \n
ewline до того, как все вхождения is
этого предшествуют нулю или одному знаку препинания, за которым следует пробел. Он делает еще один проход и удаляет все электронные \n
строки, которым непосредственно предшествует непробельный символ. Эти оставленные маркеры будут совпадать is.
иis
, но не this
или ?is
.
Затем он собирает каждый маркер в конец строки - для каждого \ni
совпадения в строке он добавляет линию \n
ewline к концу строки и заменяет ее либо на, i
либо на u
. Если в \n
конце строки собраны 3 строки, тогда используется символ u, иначе - i. Первый раз, когда используется au, также является последним - замена запускает бесконечный цикл, который сводится к get line, print line, get line, print line,
и так далее.
В конце каждого цикла цикла try он очищает вставленные пробелы, печатает только до первой встречающейся новой строки в пространстве шаблона и возвращается снова.
Я добавлю 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
es в строке:
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'
)
Это практически то же самое, но написано с помощью 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