String-Ersetzung durch .subst in einer for-Schleife

8

Ich möchte eine Zeichenfolgenersetzung in einem forBlock mithilfe eines benannten Captures vornehmen . Ich habe erwartet, die Zahlen 1,2,3 als Ausgabe zu erhalten. Aber es ist Nilfür den ersten Lauf und dann 1 und 2 für den 2. und 3. Lauf. Wie verwende ich .substdas Konstrukt korrekt in der Schleife? Ich sehe das gleiche Verhalten, wenn ich ein mapKonstrukt anstelle der forSchleife verwende. Es funktioniert wie erwartet, wenn ich durch einen festen Zeichenfolgenwert ersetze.

for <a1 b2 c3> -> $var {
    say $var;
    say $var.subst(/.$<nr>=(\d)/, $<nr>); #.subst(/.$<nr>=(\d)/, 'X'); #OK      
}

#`[
This is Rakudo version 2019.11 built on MoarVM version 2019.11   
Output:

a1
Use of Nil in string context
  in block  at test3.pl6 line 3

b2
1
c3
2
]
Valle Lukas
quelle
Ich bin neugierig. Was ist $ <nr>? (Ich konnte es nicht in der Raku-Dokumentation finden.)
p6steve
2
@ p6steve namens Capture
Valle Lukas
docs.raku.org/language/… - danke @valle - jetzt gefunden!
p6steve
Vielleicht erwägen, S///manchmal zu verwenden. In diesem Fall könnten Sie tunS[.$<nr>=(\d)] = $<nr> given $var
Jo King
@ JoKing Schön. Ich habe Ihren Kommentar positiv bewertet und dann die positive Bewertung rückgängig gemacht, weil mir klar wurde, dass ich etwas überprüfen wollte (was sich als unwichtig herausstellte), und jetzt kann SO meine positive Bewertung nicht wieder aufnehmen. Also schreibe ich dies, um Ihren netten Vorschlag manuell +1 zu machen. Ich habe es auch in meine Antwort integriert.
Raiph

Antworten:

9

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 substRoutine 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, Nilweil zu Beginn eines Programms die aktuelle Übereinstimmungsobjektvariable an etwas gebunden ist, das ihren Wert beansprucht, Nilund 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 substjemals gelaufen sind .

Sobald Raku diese Liste von Argumenten zusammengestellt hat, versucht er aufzurufen subst. Es ist erfolgreich und substläuft.

Um das nächste Match zu erhalten, wird substder 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 substnächstes das Substitutionsargument betrachtet. Es findet es Nilund 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 SSyntaxen 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, substmit diesen Argumenten aufzurufen, und dies gelingt ihm.

Als nächstes substbeginnt 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 substder 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 substwurde, 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 .

Raiph
quelle