Um Zuweisungen wie title = "Blue = Green" zu extrahieren, erfassen Sie Schlüssel und den vollständigen Wert in Anführungszeichen gemeinsam. Diese Anleitung für den Mac verwendet JavaScript in Safari, um interne Gleichheitszeichen, Anführungszeichen und Backslashes beizubehalten und fehlerhafte Zeilen zu melden.

Warum geht beim Aufteilen an Gleichheitszeichen der Wert verloren?

Betrachten Sie diese synthetische Zuweisung:

title = "Blue = Green"

Der vorgesehene Schlüssel ist title; der Wert einschließlich der ursprünglichen Anführungszeichen ist "Blue = Green". Nur das erste Gleichheitszeichen trennt die Felder. Das zweite gehört zum Text in Anführungszeichen.

JavaScripts split("=") teilt bei jedem Vorkommen, ohne Anführungszeichen auszuwerten. Wird wie in split("=", 2) ein Limit angegeben, wird das resultierende Array gekürzt; alles nach dem ersten Trennzeichen bleibt dadurch nicht erhalten. Das entspricht der Definition von String.prototype.split im Standard.

Die richtige Methode hängt von der Grammatik der Eingabe ab. Verwenden Sie diese Entscheidungshilfe, bevor Sie den Text ändern:

Eingabebedingung Geeigneter Ansatz
Eine Zuweisung pro Zeile; nur die Trennung ist relevant Suchen Sie das erste Gleichheitszeichen und übernehmen Sie den gesamten Rest.
Eine Zuweisung pro Zeile; Anführungszeichen und Schlüsselsyntax müssen ebenfalls geprüft werden Erfassen Sie wie unten die vollständige Zeile mit einem festgelegten Zuweisungsmuster.
Mehrere Zuweisungen pro Zeile oder Werte über mehrere Zeilen Verwenden Sie einen Parser, der für diese zusätzlichen Regeln ausgelegt ist.

Für diese Aufgabe bietet die Validierung der vollständigen Zeile eine zusätzliche nützliche Prüfung: Ein nicht geschlossenes Anführungszeichen oder unerwarteter nachfolgender Text erzeugt einen Fehler statt einer unvollständigen Extraktion.

Welche Zuweisungsgrammatik berücksichtigt dieses Beispiel?

Das folgende Programm implementiert ein bewusst kleines Textformat. Dies sind die dafür festgelegten Regeln und keine Behauptung, dass damit jede JavaScript-Zuweisung geparst wird:

  • Jede nicht leere Zeile enthält eine Zuweisung.
  • Schlüssel beginnen mit einem ASCII-Buchstaben oder Unterstrich, gefolgt von ASCII-Buchstaben, Ziffern oder Unterstrichen.
  • Werte verwenden passende gerade einfache oder doppelte Anführungszeichen. Leere Werte in Anführungszeichen sind gültig.
  • Innerhalb eines Werts wird ein Backslash mit dem nächsten Zeichen gepaart, außer dieses ist ein Wagenrücklauf oder Zeilenumbruch. Beide Zeichen bleiben unverändert.
  • Leerzeichen und Tabulatoren dürfen den Schlüssel, das Trennzeichen und den Wert umgeben. Leerzeichen und Tabulatoren innerhalb der Anführungszeichen bleiben Bestandteil des Werts.
  • Physische Zeilenenden dürfen LF, CRLF oder CR sein. Werte in Anführungszeichen dürfen nicht über diese Zeilenenden hinausgehen.
  • Kommentare, Semikolons und Werte ohne Anführungszeichen gehören nicht zu dieser Grammatik.

Zum Beispiel ist caption='Small = calm' gültig. Ebenso note="Use \"a=b\" here": Die maskierten doppelten Anführungszeichen gehören zum Wert. Dagegen hat caption='Small = calm" nicht übereinstimmende Begrenzungszeichen und muss korrigiert werden.

Die Ausgabe speichert jeden Wert als rawValue, einschließlich der umschließenden Anführungszeichen. Die Extraktion dekodiert keine Escape-Sequenzen: Die beiden Zeichen \n bleiben zwei Zeichen. So eignet sich das Ergebnis zum Umstellen von Zuweisungstext, ohne dessen Schreibweise zu verändern.

Doppelte Schlüssel bleiben ebenfalls separate Einträge in ihrer ursprünglichen Reihenfolge. So wird verhindert, dass ein früherer Wert unbemerkt ersetzt wird, wenn derselbe Schlüssel erneut vorkommt.

Wie führen Sie die Umwandlung in Safari auf einem Mac aus?

Der Web-Inspector von Safari bietet eine Möglichkeit, JavaScript auszuführen. Aktivieren Sie ihn über Safari → Einstellungen … → Erweitert → Funktionen für Webentwickler anzeigen. Wählen Sie anschließend Entwickler → Web-Inspector einblenden oder drücken Sie Option-Befehl-I. Diese Schritte sind in WebKits Web-Inspector aktivieren dokumentiert.

Wählen Sie den Tab Konsole und verwenden Sie das Eingabefeld, um das vollständige Programm unten einzugeben. WebKit beschreibt dieses Feld in der Referenz zur Web-Inspector-Oberfläche als Eingabefeld zum Ausführen von JavaScript. Das Beispiel verarbeitet ausschließlich die im Programm angegebene Zeichenfolge.

Das Beispiel verwendet String.raw, damit Backslashes bei der Erstellung der JavaScript-Zeichenfolge erhalten bleiben. Beachten Sie beim Bearbeiten des Beispiels, dass Backticks und ${...} weiterhin eine Bedeutung in Template-Literalen haben; diese Eingabe enthält keines von beiden. Lesen Sie die Dokumentation zu JavaScript String.raw(), bevor Sie diese Zeichen hinzufügen.

(() => {
  const source = String.raw`title = "Blue = Green"
caption='Small = calm'
note = "Use \"a=b\" here"
marker = "$1 = $$"
empty = ""`;

  const assignment = /^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*=[ \t]*("(?:\\[^\r\n]|[^"\\\r\n])*"|'(?:\\[^\r\n]|[^'\\\r\n])*')[ \t]*$/;

  function extractAssignments(text) {
    const pairs = [];
    const errors = [];
    const lines = text.split(/\r\n|\n|\r/);

    lines.forEach((line, index) => {
      if (/^[ \t]*$/.test(line)) return;
      const match = assignment.exec(line);
      if (!match || match[0].length !== line.length) {
        errors.push(`Line ${index + 1}: expected key = quoted value`);
        return;
      }
      pairs.push({ key: match[1], rawValue: match[2] });
    });

    if (errors.length) throw new Error(errors.join("\n"));
    return pairs;
  }

  const pairs = extractAssignments(source);
  const extracted = pairs
    .map(({ key, rawValue }) => `key: ${key}\nvalue: ${rawValue}`)
    .join("\n\n");
  console.log(extracted);

  const normalized = source.split(/\r\n|\n|\r/)
    .map(line => line.replace(assignment,
      (_whole, key, rawValue) => key + " = " + rawValue))
    .join("\n");
  console.log("Normalized assignments:\n" + normalized);
})();

Dies ist ein vollständiges Programm mit Beispieldaten, das keine Importe oder zusätzlichen Pakete benötigt. Die umschließende Funktion hält die Deklarationen lokal, sodass das ganze Beispiel nach dem Bearbeiten der Beispieldaten erneut ausgeführt werden kann.

Die erste Konsolenausgabe trennt die Felder:

key: title
value: "Blue = Green"

key: caption
value: 'Small = calm'

key: note
value: "Use \"a=b\" here"

key: marker
value: "$1 = $$"

key: empty
value: ""

Die zweite Ausgabe zeigt Zuweisungen mit einheitlichen Abständen:

Normalisierte Zuweisungen:
title = "Blue = Green"
caption = 'Small = calm'
note = "Use \"a=b\" here"
marker = "$1 = $$"
empty = ""

Wählen und kopieren Sie den Textblock, der zur Desktop-Aufgabe passt. Das Programm zeigt Ergebnisse über console.log an, wie WebKit in der API des Console-Objekts dokumentiert. Es schreibt keine Datei.

Wie sorgt das Muster dafür, dass Gleichheitszeichen in Anführungszeichen erhalten bleiben?

Das Muster enthält zwei Erfassungsgruppen: eine für den Schlüssel und eine für den vollständigen Wert in Anführungszeichen. Die internen (?:...)-Gruppen strukturieren Alternativen, ohne zusätzliche erfasste Felder zu erzeugen. Diese Verwendung von Erfassungs- und nicht erfassenden Gruppen entspricht der Dokumentation zu JavaScript-Gruppen.

Nach dem Erfassen des Schlüssels verarbeitet das Muster das Zuweisungstrennzeichen genau einmal. Danach wählt es entweder den Zweig für doppelte oder den für einfache Anführungszeichen. Jeder Zweig akzeptiert gewöhnliche Zeichen, einschließlich Gleichheitszeichen, oder einen Backslash zusammen mit dem folgenden Zeichen. Ein nicht maskiertes passendes Anführungszeichen schließt den jeweiligen Zweig.

Diese Struktur verarbeitet maskierte Anführungszeichen, ohne sie als Ende des Werts zu behandeln. Sie verarbeitet auch paarweise Backslashes: Nachdem ein Paar gemeinsam erfasst wurde, kann ein folgendes nicht maskiertes Anführungszeichen die Zeichenfolge schließen. Leere Werte funktionieren, weil der Inhalt in Anführungszeichen nullmal oder häufiger vorkommen darf.

Das Programm liest die Erfassungen über match[1] und match[2] aus. Ein fehlgeschlagener Aufruf von exec() gibt null zurück, wie in ECMAScript RegExp.prototype.exec festgelegt. Der zusätzliche Längenvergleich stellt sicher, dass der Treffer die gesamte physische Zeile abdeckt.

Nur Leerzeichen und Tabulatoren gelten als umgebende Formatierung. Das Programm entfernt niemals Leerraum im Inneren eines Werts. Daher behält label = " Blue = Green " die Leerzeichen an beiden Enden des Inhalts in Anführungszeichen bei.

Warum beim Umformatieren eine Ersetzungsfunktion verwenden?

Der Normalisierungsschritt gibt den erfassten Schlüssel, ein standardisiertes Trennzeichen und den erfassten Wert zurück. Der Rückruf für den Ersetzungstext erhält zuerst den vollständigen Treffer, gefolgt von den beiden Erfassungen. JavaScript dokumentiert diese Argumentreihenfolge in String.prototype.replace().

Der von einem Rückruf zurückgegebene Text wird wörtlich eingefügt, ohne Ersetzungstoken wie $1 oder $$ auszuwerten. So bleibt der Beispielwert "$1 = $$" unverändert. Dieselbe Dokumentation erklärt diesen Unterschied zwischen Ersetzungszeichenfolgen und Ersetzungsfunktionen.

Eine feste Ersetzungsvorlage wie "$1 = $2" würde für dieses Muster ebenfalls funktionieren: Erfasste Inhalte werden ohne einen zweiten Ersetzungsvorgang eingefügt. Ein Rückruf ist besonders nützlich, wenn der Ersetzungstext dynamisch zusammengesetzt wird, weil der zurückgegebene Wert dadurch von der Syntax der Ersetzungsvorlage getrennt bleibt.

Die Normalisierung ändert absichtlich umgebende Abstände und wandelt physische Zeilenenden in LF um. Sie bewahrt leere Zeilen und den genauen Text der Werte in Anführungszeichen. Wenn die ursprünglichen Abstände und Zeilenenden erhalten bleiben müssen, verwenden Sie die extrahierten Paare zur Prüfung und lassen Sie die ursprüngliche source unverändert.

Was sollten Sie prüfen, bevor Sie das Ergebnis verwenden?

Die Extraktionsfunktion sammelt Fehler mit Zeilennummern und löst eine Ausnahme aus, bevor eines der Ergebnisse ausgegeben wird. Leere Zeilen, die nur Leerzeichen oder Tabulatoren enthalten, werden ausdrücklich ignoriert. Eine fehlerhafte nicht leere Zeile kann daher nicht unbemerkt in einem scheinbar erfolgreichen Teilergebnis verschwinden.

Verwenden Sie diese synthetischen Fälle, um unerwartete Eingaben zu diagnostizieren:

Zuweisungstext Erwartetes Ergebnis
x="a=b=c" Den vollständigen Wert in Anführungszeichen erhalten.
x='' Einen leeren Wert in einfachen Anführungszeichen akzeptieren.
x=" a=b " Die Leerzeichen innerhalb der Anführungszeichen erhalten.
x="a\"=b" Das maskierte Anführungszeichen und Gleichheitszeichen erhalten.
x="a=b Das fehlende schließende Anführungszeichen melden.
x="a" extra Nachfolgenden Text melden.
x="a" y="b" Mehrere Zuweisungen in einer Zeile zurückweisen.
x=a=b Einen Wert ohne Anführungszeichen gemäß dieser Grammatik zurückweisen.

Die Extraktions- und Normalisierungslogik des Programms wurde mit dem gezeigten Beispiel in Node.js 20.19.2 ausgeführt. Fünfzehn zusätzliche deterministische Prüfungen deckten Gleichheitszeichen in Anführungszeichen, leere Werte, maskierte Anführungszeichen, paarweise Backslashes, wörtliche Dollar-Token, fehlerhafte Zeilen, doppelte Schlüssel und den Umgang mit Leerzeilen ab. Das überprüft die festgelegte Umwandlungslogik; es bedeutet nicht, dass die Safari-Oberfläche ausprobiert wurde.

Wenn eine Zeile fehlschlägt, prüfen Sie zuerst die Begrenzungszeichen und suchen Sie danach nach einem abschließenden ungepaarten Backslash, nachfolgendem Text oder einem nicht unterstützten Schlüssel. Ändern Sie die Grammatik bewusst, wenn die Aufgabe weitere Syntax erfordert. Für das beschriebene Format mit einer Zuweisung pro Zeile ist das Ergebnis ein wiederverwendbares Paar von Feldern, dessen Wert in Anführungszeichen jedes interne Gleichheitszeichen beibehält.

Quellen