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 sed
carrega apenas um registro de is
ocorrências de uma linha para a seguinte. Ele deve manipular confiavelmente o número de is
es 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 is
que 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 is
es válidas inserindo uma \n
linha de e-mail antes que todas as ocorrências is
precedam imediatamente zero ou um caractere de pontuação, seguidos por um espaço. Ele faz outra passagem e remove todas as \n
linhas de ew que são imediatamente precedidas por um caractere não espaço. Esses marcadores deixados para trás corresponderão is.
e is
mas não this
ou ?is
.
Em seguida, ele reúne cada marcador \ni
no final da sequência - para cada partida em uma linha, ele anexa uma linha de \n
ew ao final da sequência e o substitui por um i
ou u
. Se houver três \n
linhas 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 l
comando 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 is
es 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