Per estrarre assegnazioni come title = "Blue = Green", fai corrispondere insieme la chiave e l'intero valore tra virgolette. Questa guida per Mac usa JavaScript in Safari per preservare i segni di uguale, le virgolette e le barre rovesciate interne, segnalando le righe malformate.

Perché la divisione sui segni di uguale fa perdere il valore?

Considera questa assegnazione sintetica:

title = "Blue = Green"

La chiave prevista è title; il valore, incluse le virgolette originali, è "Blue = Green". Solo il primo segno di uguale separa i campi. Il secondo appartiene al testo tra virgolette.

split("=") di JavaScript divide in corrispondenza di ogni occorrenza senza interpretare le virgolette. Aggiungere un limite, come in split("=", 2), tronca l'array risultante; non conserva tutto ciò che segue il primo separatore. Questo è conforme alla definizione di String.prototype.split dello standard.

Il metodo giusto dipende dalla grammatica dell'input. Consulta questa guida decisionale prima di modificare il testo:

Condizione dell'input Approccio appropriato
Un'assegnazione per riga; conta solo la separazione Individua il primo segno di uguale e conserva tutto il resto.
Un'assegnazione per riga; occorre verificare anche le virgolette e la sintassi della chiave Fai corrispondere l'intera riga a un pattern di assegnazione definito, come quello qui sotto.
Più assegnazioni per riga o valori su più righe Usa un parser progettato per gestire queste regole aggiuntive.

Per questo compito, la convalida dell'intera riga fornisce un controllo aggiuntivo utile: una virgoletta senza corrispondenza o del testo finale imprevisto generano un errore invece di un'estrazione incompleta.

Quale grammatica di assegnazione conserva questo esempio?

Il programma qui sotto implementa un formato di testo volutamente semplice. Queste sono le regole definite per questo esempio, non l'affermazione che analizzi ogni assegnazione JavaScript:

  • Ogni riga non vuota contiene un'assegnazione.
  • Le chiavi iniziano con una lettera ASCII o un trattino basso, seguiti da lettere ASCII, cifre o trattini bassi.
  • I valori usano virgolette dritte singole o doppie corrispondenti. I valori vuoti tra virgolette sono validi.
  • All'interno di un valore, una barra rovesciata si abbina al carattere successivo, tranne un ritorno a capo o un avanzamento riga. Entrambi i caratteri rimangono invariati.
  • Spazi e tabulazioni possono precedere o seguire la chiave, il separatore e il valore. Gli spazi e le tabulazioni tra virgolette rimangono parte del valore.
  • I terminatori di riga fisici possono essere LF, CRLF o CR. I valori tra virgolette non possono estendersi oltre tali terminatori.
  • Commenti, punti e virgola e valori senza virgolette non rientrano in questa grammatica.

Per esempio, caption='Small = calm' è valido. Anche note="Use \"a=b\" here" lo è: le virgolette doppie con escape appartengono al valore. Al contrario, caption='Small = calm" ha delimitatori non corrispondenti e deve essere corretto.

L'output memorizza ogni valore come rawValue, incluse le virgolette che lo racchiudono. L'estrazione non decodifica le sequenze di escape: i due caratteri \n rimangono due caratteri. In questo modo il risultato è adatto a riordinare il testo delle assegnazioni senza modificarne la rappresentazione scritta.

Anche le chiavi duplicate restano voci separate nell'ordine originale. Questa scelta evita di sostituire silenziosamente un valore precedente quando la stessa chiave ricompare.

Come si esegue la trasformazione in Safari su un Mac?

Web Inspector di Safari offre un ambiente in cui eseguire JavaScript. Abilitalo tramite Safari → Impostazioni… → Avanzate → Mostra le funzionalità per gli sviluppatori web. Poi scegli Sviluppo → Mostra Web Inspector oppure premi Opzione-Comando-I. Questi passaggi sono documentati in Abilitazione di Web Inspector di WebKit.

Seleziona la scheda Console e usa il relativo prompt di input per eseguire l'intero programma qui sotto. WebKit documenta il prompt come campo di input per eseguire JavaScript nel riferimento all'interfaccia di Web Inspector. L'esempio opera solo sulla stringa definita nel programma.

L'esempio usa String.raw affinché le barre rovesciate rimangano intatte durante la creazione della stringa JavaScript. Quando modifichi l'esempio, ricorda che i backtick e ${...} mantengono il significato speciale che hanno nei template literal; questo input non contiene né gli uni né gli altri. Consulta la documentazione JavaScript di String.raw() prima di aggiungere questi caratteri.

(() => {
  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);
})();

È un programma completo con dati di esempio, senza importazioni né pacchetti aggiuntivi. La funzione che lo racchiude mantiene locali le dichiarazioni e permette di rieseguire l'intero esempio dopo aver modificato i dati.

Il primo messaggio nella console separa i campi:

key: title
value: "Blue = Green"

key: caption
value: 'Small = calm'

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

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

key: empty
value: ""

Il secondo messaggio mostra le assegnazioni con spaziatura coerente:

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

Seleziona e copia il blocco di testo adatto al tuo compito sul desktop. Il programma visualizza i risultati tramite console.log, documentato da WebKit nella Console Object API. Non scrive alcun file.

In che modo il pattern mantiene intatti i segni di uguale tra virgolette?

Il pattern ha due gruppi di cattura: uno per la chiave e uno per l'intero valore tra virgolette. I suoi (?:...) interni organizzano le alternative senza creare ulteriori campi catturati. Questo uso di gruppi di cattura e non catturanti segue la documentazione JavaScript sui gruppi.

Dopo aver individuato la chiave, il pattern consuma una sola volta il separatore dell'assegnazione. Poi sceglie il ramo con virgolette doppie oppure quello con virgolette singole. Ogni ramo accetta caratteri ordinari, inclusi i segni di uguale, oppure una barra rovesciata abbinata al carattere successivo. Una virgoletta corrispondente non preceduta da escape chiude il ramo.

Questa struttura gestisce le virgolette con escape senza interpretarle come fine del valore. Gestisce anche le coppie di barre rovesciate: dopo averle consumate insieme, la virgoletta successiva non preceduta da escape può chiudere la stringa. I valori vuoti sono validi perché il contenuto tra virgolette può ripetersi zero volte.

Il programma legge i gruppi catturati tramite match[1] e match[2]. Una chiamata exec() non riuscita restituisce null, come specificato da RegExp.prototype.exec in ECMAScript. Il confronto aggiuntivo della lunghezza richiede che la corrispondenza copra l'intera riga fisica.

Solo spazi e tabulazioni sono considerati formattazione circostante. Il programma non elimina mai gli spazi all'interno di un valore. Di conseguenza, label = " Blue = Green " conserva entrambi gli spazi alle estremità del contenuto tra virgolette.

Perché usare una funzione di sostituzione per riformattare?

Il passaggio di normalizzazione restituisce la chiave catturata, un separatore standardizzato e il valore catturato. Il callback di sostituzione riceve prima la corrispondenza completa, poi i due gruppi catturati. JavaScript documenta quest'ordine degli argomenti in String.prototype.replace().

Il testo restituito da un callback viene inserito alla lettera, senza interpretare token di sostituzione come $1 o $$. In questo modo il valore di esempio "$1 = $$" rimane intatto. La stessa documentazione spiega questa distinzione tra stringhe di sostituzione e funzioni di sostituzione.

Anche un modello di sostituzione fisso come "$1 = $2" funzionerebbe con questo specifico pattern: i contenuti catturati vengono inseriti senza un secondo passaggio di sostituzione. Il callback è particolarmente utile quando si compone dinamicamente il testo sostitutivo, perché mantiene il valore restituito separato dalla sintassi del modello di sostituzione.

La normalizzazione modifica intenzionalmente la spaziatura circostante e converte i terminatori di riga fisici in LF. Conserva le righe vuote e il testo esatto dei valori tra virgolette. Se il compito richiede la spaziatura e i terminatori di riga originali, usa le coppie estratte per l'ispezione e lascia invariato l'originale source.

Cosa controllare prima di usare il risultato?

La funzione di estrazione raccoglie gli errori indicando il numero di riga e genera un'eccezione prima che venga stampato uno dei due risultati. Le righe vuote contenenti solo spazi o tabulazioni vengono ignorate esplicitamente. Di conseguenza, una riga malformata non può essere ignorata producendo un risultato parziale apparentemente corretto.

Usa questi casi sintetici per diagnosticare input imprevisti:

Testo dell'assegnazione Risultato previsto
x="a=b=c" Conserva l'intero valore tra virgolette.
x='' Accetta un valore vuoto tra virgolette singole.
x=" a=b " Conserva gli spazi tra virgolette.
x="a\"=b" Conserva la virgoletta con escape e il segno di uguale.
x="a=b Segnala la virgoletta di chiusura mancante.
x="a" extra Segnala il testo finale.
x="a" y="b" Rifiuta più assegnazioni sulla stessa riga.
x=a=b Rifiuta un valore senza virgolette secondo questa grammatica.

La logica di estrazione e normalizzazione del programma è stata eseguita in Node.js 20.19.2 con l'esempio mostrato. Quindici verifiche deterministiche aggiuntive hanno riguardato i segni di uguale tra virgolette, i valori vuoti, le virgolette con escape, le coppie di barre rovesciate, i token dollaro letterali, le righe malformate, le chiavi duplicate e la gestione delle righe vuote. Ciò verifica la logica di trasformazione definita per l'esempio; non significa che l'interfaccia di Safari sia stata provata.

Se una riga non supera la verifica, controlla prima i delimitatori, poi cerca una barra rovesciata finale senza coppia, del testo finale o una chiave non supportata. Modifica la grammatica con criterio se il compito richiede altra sintassi. Per il formato dichiarato, con un'assegnazione per riga, il risultato è una coppia riutilizzabile di campi il cui valore tra virgolette conserva ogni segno di uguale interno.

Fonti