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'
Dieses Bit von sed
trägt nur eine Liste von is
Ereignissen von einer Zeile zur nächsten. Es sollte zuverlässig so viele is
es pro Zeile verarbeiten, wie Sie darauf werfen, und es muss dabei keine alten Zeilen puffern - es behält nur ein einzelnes Zeilenumbruchzeichen für jedes is
, auf das es trifft, das nicht Teil eines anderen Wortes ist.
Das Ergebnis ist, dass nur das dritte Vorkommen in einer Datei geändert wird - und die Anzahl pro Zeile übertragen wird. Wenn also eine Datei so aussieht:
1. is is isis
2. is does
... es wird gedruckt ...
1. is is isis
2. us does
Zunächst werden Randfälle behandelt, indem am Kopf und am Ende jeder Zeile ein Leerzeichen eingefügt wird. Dies erleichtert die Ermittlung von Wortgrenzen.
Als nächstes wird nach gültigen is
es \n
gesucht, indem eine Ewline eingefügt wird, bevor alle Vorkommen is
unmittelbar vor null oder einem Satzzeichen stehen, gefolgt von einem Leerzeichen. Es führt einen weiteren Durchgang durch und entfernt alle \n
Ewlines, denen unmittelbar ein Nicht-Leerzeichen vorangestellt ist. Diese zurückgelassenen Markierungen stimmen überein is.
und is
aber nicht this
oder ?is
.
Als nächstes wird jeder Marker am Ende der Zeichenfolge \ni
gesammelt. Bei jeder Übereinstimmung in einer Zeile wird eine \n
neue Zeile an das Ende der Zeichenfolge angehängt und durch entweder i
oder ersetzt u
. Wenn \n
sich am Ende des Strings 3 Ewlines in einer Reihe befinden, wird das u - sonst das i verwendet. Das erste Mal, wenn au verwendet wird, ist auch das letzte Mal - der Ersatz löst eine Endlosschleife aus, die auf get line, print line, get line, print line,
usw. hinausläuft.
Am Ende jedes Try-Loop-Zyklus werden die eingefügten Leerzeichen bereinigt, nur bis zur ersten auftretenden neuen Zeile im Musterbereich gedruckt und erneut ausgeführt.
Ich werde einen l
ook-Befehl am Kopf der Schleife hinzufügen wie:
l; s/\ni(.* )\n{9}/u\1/...
... und schauen Sie sich an, was es mit dieser Eingabe macht:
hai this is linux.
hai this is unix.
hai this is mac.
hai this is unchanged is.
... also hier ist was es tut:
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
Es macht vielleicht mehr Sinn mit mehr is
es pro Zeile:
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'
)
Das ist praktisch das Gleiche, aber mit POSIX BRE und rudimentärer Argumentation geschrieben.
printf 'is is. is? this is%.0s\n' {1..4} | nthword is us 12
... bekommt ...
is is. is? this is
is is. is? this is
is is. is? this us
is is. is? this is
... und wenn ich aktiviere ${dbg}
:
printf 'is is. is? this is%.0s\n' {1..4} |
dbg=1 nthword is us 12
... wir können es iterieren sehen ...
\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