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'
Essa parte sedcarrega apenas um registro de isocorrências de uma linha para a seguinte. Ele deve manipular confiavelmente o número de ises por linha que você lançar nela, e não precisa armazenar em buffer as linhas antigas enquanto o faz - apenas retém um único caractere de nova linha para cada um isque encontrar que não faça parte de outra palavra.
O resultado é que ele modificará apenas a terceira ocorrência em um arquivo - e contará por linha. Portanto, se um arquivo se parecer com:
1. is is isis
2. is does
... será impresso ...
1. is is isis
2. us does
Primeiro ele lida com casos de borda, inserindo um espaço na cabeça e no final de cada linha. Isso facilita a verificação dos limites das palavras.
A seguir, procura ises válidas inserindo uma \nlinha de e-mail antes que todas as ocorrências isprecedam imediatamente zero ou um caractere de pontuação, seguidos por um espaço. Ele faz outra passagem e remove todas as \nlinhas de ew que são imediatamente precedidas por um caractere não espaço. Esses marcadores deixados para trás corresponderão is.e ismas não thisou ?is.
Em seguida, ele reúne cada marcador \nino final da sequência - para cada partida em uma linha, ele anexa uma linha de \new ao final da sequência e o substitui por um iou u. Se houver três \nlinhas de linha seguidas no final da corda, ele usará o u - senão o i. A primeira vez que au é usada também é a última - a substituição desencadeia um loop infinito que se resume a get line, print line, get line, print line,e assim por diante.
No final de cada ciclo de loop de tentativa, limpa os espaços inseridos, imprime apenas até a primeira nova linha que ocorrer no espaço do padrão e continua novamente.
Vou adicionar um lcomando ook na cabeça do loop, como:
l; s/\ni(.* )\n{9}/u\1/...
... e dê uma olhada no que faz, pois funciona com esta entrada:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged is.
... então aqui está o que ele faz:
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
Faz mais sentido, talvez com mais ises por linha:
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'
)
Isso é praticamente a mesma coisa, mas escrito com POSIX BRE e manipulação rudimentar de argumentos.
printf 'is is. is? this is%.0s\n' {1..4} | nthword is us 12
... fica ...
is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is
... e se eu ativar ${dbg}:
printf 'is is. is? this is%.0s\n' {1..4} |
dbg=1 nthword is us 12
... podemos assistir iterar ...
\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