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'
Ce morceau de sed
transporte juste un décompte des is
occurrences d'une ligne à la suivante. Il devrait gérer de manière fiable autant d' is
es par ligne que vous y jetez, et il n'a pas besoin de mettre en mémoire tampon les anciennes lignes pendant qu'il le fait - il conserve juste un seul caractère de nouvelle ligne pour tout is
ce qu'il rencontre qui ne fait pas partie d'un autre mot.
Le résultat est qu'il ne modifiera que la troisième occurrence dans un fichier - et il portera des comptes par ligne. Donc, si un fichier ressemble à:
1. is is isis
2. is does
... il imprimera ...
1. is is isis
2. us does
Il gère d'abord les cas de bord en insérant un espace à la tête et à la queue de chaque ligne. Cela rend les limites des mots un peu plus faciles à déterminer.
Il recherche ensuite les is
es valides en insérant une ligne \n
électronique avant que toutes les occurrences de is
celle-ci ne précèdent immédiatement zéro ou un caractère de ponctuation suivi d'un espace. Il fait un autre passage et supprime tous les \n
ewlines qui sont immédiatement précédés d'un caractère non-espace. Ces marqueurs laissés correspondront is.
et is
mais pas this
ou ?is
.
Il rassemble ensuite chaque marqueur à la queue de la chaîne - pour chaque \ni
correspondance sur une ligne, il ajoute une ligne \n
électronique à la queue de la chaîne et la remplace par soit par i
ou u
. S'il y a 3 \n
lignes électroniques consécutives rassemblées à la fin de la chaîne, alors il utilise le u - sinon le i. La première fois que au est utilisé est également le dernier - le remplacement déclenche une boucle infinie qui se résume à get line, print line, get line, print line,
et ainsi de suite.
À la fin de chaque cycle de boucle d'essai, il nettoie les espaces insérés, imprime uniquement jusqu'à la première nouvelle ligne apparaissant dans l'espace de motif et recommence.
Je vais ajouter une l
commande ook en tête de boucle comme:
l; s/\ni(.* )\n{9}/u\1/...
... et jetez un œil à ce qu'il fait car il fonctionne avec cette entrée:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged is.
... alors voici ce que ça fait:
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
Cela a plus de sens peut-être avec plus d' is
es par ligne:
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'
)
C'est pratiquement la même chose, mais écrit avec POSIX BRE et une gestion rudimentaire des arguments.
printf 'is is. is? this is%.0s\n' {1..4} | nthword is us 12
... obtient ...
is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is
... et si j'active ${dbg}
:
printf 'is is. is? this is%.0s\n' {1..4} |
dbg=1 nthword is us 12
... nous pouvons le regarder itérer ...
\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