TL; DR Verschiebung der Auswertung $<nr>
bis nach Auswertung des Regex. @ JoKing ++ schlägt einen Weg vor . Eine andere Möglichkeit besteht darin, den Ersatz einfach mit Klammern ( {$<nr>}
) zu umwickeln .
Was passiert, wenn Ihr ursprünglicher Code aufruft? subst
Bevor Raku versucht, die subst
Routine aufzurufen , stellt er eine Liste von Argumenten zusammen, die an ihn übergeben werden sollen.
Es gibt zwei Werte. Der erste ist eine Regex. Es ist nicht laufen . Der zweite Wert ist $<nr>
. Es wird ausgewertet, Nil
weil zu Beginn eines Programms die aktuelle Übereinstimmungsobjektvariable an etwas gebunden ist, das ihren Wert beansprucht, Nil
und jeder Versuch, auf den Wert eines Schlüssels darin zuzugreifen, $<nr>
ebenfalls zurückgegeben wird Nil
. Zu diesem Zeitpunkt sind die Dinge also schon schief gelaufen, bevor sie subst
jemals gelaufen sind .
Sobald Raku diese Liste von Argumenten zusammengestellt hat, versucht er aufzurufen subst
. Es ist erfolgreich und subst
läuft.
Um das nächste Match zu erhalten, wird subst
der Regex ausgeführt. Dadurch wird die aktuelle Übereinstimmungsobjektvariable aktualisiert $/
. Es ist jedoch zu spät, um den bereits übergebenen Substitutionswert zu ändern subst
.
Mit Match in der Hand wird als subst
nächstes das Substitutionsargument betrachtet. Es findet es Nil
und handelt entsprechend.
Für den zweiten Aufruf subst
, $<nr>
hat auf dem Wert aus dem aufgenommenen ersten Aufruf subst
. Und so weiter.
Zwei Möglichkeiten, die Bewertung von zu verschieben $<nr>
@JoKing schlägt vor, die Verwendung von in Betracht zu ziehen S///
. Dieses Konstrukt wertet zuerst den regulären Ausdruck (zwischen dem ersten Paar von /
s) und dann den Ersatz (zwischen dem letzten Paar von /
s) aus. (Das gleiche Prinzip gilt, wenn Sie andere gültige S
Syntaxen wie verwenden S[...] = ...
.)
Wenn Sie verwenden subst
, stellt Raku, wie im vorherigen Abschnitt erläutert, die Argumentliste dafür zusammen, bevor Sie sie aufrufen. Es findet einen regulären Ausdruck (den es nicht ausführt) und einen Abschluss (den es auch nicht ausführt). Es versucht dann, subst
mit diesen Argumenten aufzurufen, und dies gelingt ihm.
Als nächstes subst
beginnt zu laufen. Es hat Code sowohl für das Match (eine Regex) als auch für die Substitution (ein Closure) erhalten.
Es führt den regulären Ausdruck als Matching-Operation aus. Wenn der reguläre Ausdruck eine Übereinstimmung zurückgibt, wird subst
der Abschluss ausgeführt und der zurückgegebene Wert als Ersetzung verwendet.
Da wir also von der Übergabe $<nr>
als nackter Wert, was bedeutete, dass er eingefroren wurde Nil
, zur Übergabe in einen Verschluss übergegangen sind, der seine Bewertung verschoben hat $/
, bis eine Übereinstimmung mit einem ausgefüllten <nr>
Eintrag festgelegt wurde, haben wir das Problem gelöst.
Beachten Sie, dass dies nur funktioniert, weil derjenige, der entworfen / implementiert subst
wurde, klug / nett genug war, um zuzulassen, dass sowohl die Übereinstimmungs- als auch die Substitutionsargumente Formen von Code
(ein regulärer Ausdruck für die Übereinstimmung und ein gewöhnlicher Abschluss für die Substitution) sind, wenn ein Benutzer dies wünscht. Es führt dann zuerst das Match aus und führt dann nur dann den Substitutionsabschluss aus, wenn einer bestanden wurde, wobei das Ergebnis dieses letzteren Aufrufs als endgültige Substitution verwendet wird. Auf ähnliche Weise S///
funktioniert , weil das nur entwickelt wurde , um den Austausch zu bewerten , nachdem er zunächst die Substitution ausgewertet wird .