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 sedtransporte juste un décompte des isoccurrences d'une ligne à la suivante. Il devrait gérer de manière fiable autant d' ises 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 isce 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 ises valides en insérant une ligne \nélectronique avant que toutes les occurrences de iscelle-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 \newlines qui sont immédiatement précédés d'un caractère non-espace. Ces marqueurs laissés correspondront is.et ismais pas thisou ?is.
Il rassemble ensuite chaque marqueur à la queue de la chaîne - pour chaque \nicorrespondance sur une ligne, il ajoute une ligne \nélectronique à la queue de la chaîne et la remplace par soit par iou u. S'il y a 3 \nlignes é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 lcommande 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' ises 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