Ich möchte wissen, wie man eine Erfassungsgruppe in JavaScript durch Großbuchstaben ersetzt. Hier ist eine vereinfachte Version von dem, was ich bisher versucht habe und was nicht funktioniert:
> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'
Würden Sie erklären, was mit diesem Code nicht stimmt?
javascript
regex
replace
uppercase
Evan Carroll
quelle
quelle
Antworten:
Sie können eine Funktion an übergeben
replace
.var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });
Erläuterung
a.replace( /(f)/, "$1".toUpperCase())
In diesem Beispiel übergeben Sie eine Zeichenfolge an die Ersetzungsfunktion. Da Sie die spezielle Ersetzungssyntax verwenden ($ N greift nach dem N-ten Capture), geben Sie einfach den gleichen Wert an. Das
toUpperCase
täuscht tatsächlich, weil Sie nur die Ersetzungszeichenfolge in Großbuchstaben schreiben (was etwas sinnlos ist, da die Zeichen$
und ein1
Zeichen keine Großbuchstaben haben, sodass der Rückgabewert weiterhin erhalten bleibt"$1"
) .a.replace( /(f)/, String.prototype.toUpperCase.apply("$1"))
Ob Sie es glauben oder nicht, die Semantik dieses Ausdrucks ist genau dieselbe.
quelle
$1
die erste Erfassungsgruppe.Ich weiß, dass ich zu spät zur Party komme, aber hier ist eine kürzere Methode, die eher Ihren ersten Versuchen entspricht.
a.replace('f', String.call.bind(a.toUpperCase));
Wo hast du etwas falsch gemacht und was ist das für ein neues Voodoo?
Problem 1
Wie bereits erwähnt, haben Sie versucht, die Ergebnisse einer aufgerufenen Methode als zweiten Parameter von String.prototype.replace () zu übergeben , wenn Sie stattdessen einen Verweis auf eine Funktion übergeben sollten
Lösung 1
Das ist leicht zu lösen. Durch einfaches Entfernen der Parameter und Klammern erhalten wir eine Referenz, anstatt die Funktion auszuführen.
a.replace('f', String.prototype.toUpperCase.apply)
Problem 2
Wenn Sie versuchen, den Code jetzt auszuführen, wird eine Fehlermeldung angezeigt, dass undefined keine Funktion ist und daher nicht aufgerufen werden kann. Dies liegt daran, dass String.prototype.toUpperCase.apply tatsächlich ein Verweis auf Function.prototype.apply () über die prototypische Vererbung von JavaScript ist. Was wir also tatsächlich tun, sieht eher so aus
a.replace('f', Function.prototype.apply)
Welches ist offensichtlich nicht das, was wir beabsichtigt haben. Woher weiß es, Function.prototype.apply () auf String.prototype.toUpperCase () auszuführen ?
Lösung 2
Mit Function.prototype.bind () können wir eine Kopie von Function.prototype.call erstellen, deren Kontext speziell auf String.prototype.toUpperCase festgelegt ist. Wir haben jetzt folgendes
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problem 3
Das letzte Problem ist, dass String.prototype.replace () mehrere Argumente an seine Ersetzungsfunktion übergibt . Function.prototype.apply () erwartet jedoch, dass der zweite Parameter ein Array ist, erhält jedoch entweder eine Zeichenfolge oder eine Zahl (je nachdem, ob Sie Erfassungsgruppen verwenden oder nicht). Dies würde einen ungültigen Argumentlistenfehler verursachen.
Lösung 3
Glücklicherweise können wir Function.prototype.apply () einfach in Function.prototype.call () ersetzen (das eine beliebige Anzahl von Argumenten akzeptiert, von denen keines Typeinschränkungen aufweist) . Wir sind jetzt beim Arbeitscode angekommen!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Bytes verlieren!
Niemand möchte ein paar Mal einen Prototyp schreiben. Stattdessen nutzen wir die Tatsache, dass wir Objekte haben, die über die Vererbung auf dieselben Methoden verweisen. Der String-Konstruktor ist eine Funktion und erbt vom Prototyp der Funktion. Dies bedeutet, dass wir Function.prototype.call in String.call ersetzen können (tatsächlich können wir Date.call verwenden, um noch mehr Bytes zu speichern, aber das ist weniger semantisch).
Wir können auch unsere Variable 'a' nutzen, da ihr Prototyp einen Verweis auf String.prototype.toUpperCase enthält. Wir können diesen mit a.toUpperCase austauschen. Durch die Kombination der drei oben genannten Lösungen und dieser Maßnahmen zum Speichern von Bytes erhalten wir den Code oben in diesem Beitrag.
quelle
Alter Beitrag, aber es lohnt sich, die @ ChaosPandion-Antwort für andere Anwendungsfälle mit eingeschränkterem RegEx zu erweitern. Stellen Sie beispielsweise sicher, dass die
(f)
oder die Erfassung der Gruppenumgebung ein bestimmtes Format aufweist/z(f)oo/
:> a="foobazfoobar" 'foobazfoobar' > a.replace(/z(f)oo/, function($0,$1) {return $0.replace($1, $1.toUpperCase());}) 'foobazFoobar' // Improve the RegEx so `(f)` will only get replaced when it begins with a dot or new line, etc.
Ich möchte nur die beiden Parameter hervorheben, die es
function
ermöglichen, ein bestimmtes Format zu finden und eine Erfassungsgruppe innerhalb des Formats zu ersetzen.quelle
return $0.replace($0, $1.toUpperCase())
, wo$0
ist das erste ArgumentWarum schlagen wir nicht einfach die Definition nach ?
Wenn wir schreiben:
a.replace(/(f)/, x => x.toUpperCase())
wir könnten genauso gut einfach sagen:
a.replace('f','F')
Schlimmer noch, ich vermute, niemand merkt, dass ihre Beispiele nur funktioniert haben, weil sie den gesamten regulären Ausdruck in Klammern festgehalten haben . Wenn Sie sich die Definition ansehen , ist der erste Parameter, der an die
replacer
Funktion übergeben wird, das gesamte übereinstimmende Muster und nicht das Muster, das Sie in Klammern erfasst haben:function replacer(match, p1, p2, p3, offset, string)
Wenn Sie die Pfeilfunktionsnotation verwenden möchten:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()
quelle
LÖSUNG
a.replace(/(f)/,x=>x.toUpperCase())
Verwenden Sie
/(f)/g
regexp, um alle grup-Vorkommen zu ersetzen. Das Problem in Ihrem Code:String.prototype.toUpperCase.apply("$1")
und"$1".toUpperCase()
gibt"$1"
(versuchen Sie es in der Konsole selbst) - so ändert es nichts und Sie rufen tatsächlich zweimal aufa.replace( /(f)/, "$1")
(was auch nichts ändert).Code-Snippet anzeigen
let a= "foobar"; let b= a.replace(/(f)/,x=>x.toUpperCase()); let c= a.replace(/(o)/g,x=>x.toUpperCase()); console.log("/(f)/ ", b); console.log("/(o)/g", c);
quelle
Gegeben ein Wörterbuch (Objekt, in diesem Fall a
Map
) von Eigenschaften, Werten und Verwendung,.bind()
wie unter Antworten beschriebenconst regex = /([A-z0-9]+)/; const dictionary = new Map([["hello", 123]]); let str = "hello"; str = str.replace(regex, dictionary.get.bind(dictionary)); console.log(str);
Verwenden eines einfachen JavaScript-Objekts und einer definierten Funktion zum Abrufen des übereinstimmenden Eigenschaftswerts des Objekts oder der ursprünglichen Zeichenfolge, wenn keine Übereinstimmung gefunden wird
const regex = /([A-z0-9]+)/; const dictionary = { "hello": 123, [Symbol("dictionary")](prop) { return this[prop] || prop } }; let str = "hello"; str = str.replace(regex, dictionary[Object.getOwnPropertySymbols(dictionary)[0]].bind(dictionary)); console.log(str);
quelle