För att extrahera tilldelningar som title = "Blue = Green" matchar du nyckeln och hela det citerade värdet tillsammans. Den här Mac-guiden använder JavaScript i Safari för att bevara interna likhetstecken, citattecken och omvända snedstreck samtidigt som felaktigt formaterade rader rapporteras.

Varför går värdet förlorat när man delar vid likhetstecken?

Tänk på den här syntetiska tilldelningen:

title = "Blue = Green"

Den avsedda nyckeln är title; värdet, inklusive de ursprungliga citattecknen, är "Blue = Green". Det är bara det första likhetstecknet som skiljer fälten åt. Det andra tillhör den citerade texten.

JavaScripts split("=") delar vid varje förekomst utan att tolka citattecken. Om du anger en gräns, som i split("=", 2), trunkeras den resulterande arrayen; allt efter den första avgränsaren bevaras inte. Detta följer standardens definition av String.prototype.split.

Rätt metod beror på indatans grammatik. Använd den här beslutshjälpen innan du ändrar texten:

Indatavillkor Lämpligt tillvägagångssätt
En tilldelning per rad; endast avgränsningen spelar roll Leta upp det första likhetstecknet och behåll hela resten.
En tilldelning per rad; även citattecken och nyckelsyntax måste kontrolleras Matcha hela raden med ett definierat tilldelningsmönster, som nedan.
Flera tilldelningar per rad eller värden som sträcker sig över flera rader Använd en parser som är utformad för de ytterligare reglerna.

För den här uppgiften ger validering av hela raden en användbar extra kontroll: ett omatchat citattecken eller oväntad efterföljande text ger ett fel i stället för en ofullständig extrahering.

Vilken tilldelningsgrammatik bevarar det här exemplet?

Programmet nedan implementerar ett avsiktligt litet textformat. Det här är reglerna som formatet definierar, inte ett påstående om att det tolkar alla JavaScript-tilldelningar:

  • Varje rad som inte är tom innehåller en tilldelning.
  • Nycklar börjar med en ASCII-bokstav eller ett understreck, följt av ASCII-bokstäver, siffror eller understreck.
  • Värden använder matchande raka enkla eller raka dubbla citattecken. Tomma citerade värden är giltiga.
  • Inuti ett värde paras ett omvänt snedstreck ihop med nästa tecken, utom en vagnretur eller radbrytning. Båda tecknen förblir oförändrade.
  • Mellanslag och tabbar får omge nyckeln, avgränsaren och värdet. Mellanslag och tabbar inuti citattecken ingår i värdet.
  • Fysiska radslut kan vara LF, CRLF eller CR. Citerade värden kan inte sträcka sig över dessa radslut.
  • Kommentarer, semikolon och ociterade värden ingår inte i grammatiken.

Exempelvis är caption='Small = calm' giltigt. Även note="Use \"a=b\" here" är giltigt: de escapade dubbla citattecknen ingår i värdet. Däremot har caption='Small = calm" omatchade avgränsare och måste korrigeras.

Utdata lagrar varje värde som rawValue, inklusive de omslutande citattecknen. Extraheringen avkodar inte escape-sekvenser: de två tecknen \n förblir två tecken. Därför passar resultatet för att ordna om tilldelningstext utan att ändra hur den är skriven.

Dubblerade nycklar förblir också separata poster i sin ursprungliga ordning. Det valet förhindrar att ett tidigare värde tyst ersätts när samma nyckel förekommer igen.

Hur kör du omvandlingen i Safari på en Mac?

Safari Web Inspector har en plats där du kan utvärdera JavaScript. Aktivera den via Safari → Settings… → Advanced → Show features for web developers. Välj sedan Develop → Show Web Inspector eller tryck på Option-Command-I. Stegen dokumenteras i WebKits Aktivera Web Inspector.

Välj fliken Console och använd inmatningsfältet för hela programmet nedan. WebKit beskriver fältet som en plats för att utvärdera JavaScript i sin referens för Web Inspector-gränssnittet. Exemplet arbetar endast med den textsträng som definieras i programmet.

Exemplet använder String.raw så att omvända snedstreck bevaras när JavaScript-strängen skapas. Tänk på att bakåtcitattecken och ${...} fortfarande har betydelse i mallitteraler när du redigerar exemplet; den här indatan innehåller ingetdera. Läs dokumentationen om JavaScript String.raw() innan du lägger till sådana tecken.

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

Det här är ett komplett program med exempeldata och utan importer eller ytterligare paket. Den omslutande funktionen håller deklarationerna lokala, så att hela exemplet kan köras igen efter att du redigerat exemplet.

Det första konsolmeddelandet skiljer fälten åt:

key: title
value: "Blue = Green"

key: caption
value: 'Small = calm'

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

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

key: empty
value: ""

Det andra meddelandet visar tilldelningar med konsekvent mellanrum:

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

Markera och kopiera det textblock som passar skrivbordsuppgiften. Programmet visar resultat via console.log, som WebKit dokumenterar i sitt API för Console-objektet. Det skriver inte någon fil.

Hur bevarar mönstret citerade likhetstecken?

Mönstret har två fångstgrupper: en för nyckeln och en för hela det citerade värdet. Dess interna (?:...)-grupper ordnar alternativen utan att skapa ytterligare fångade fält. Den här användningen av fångstgrupper och icke-fångande grupper följer dokumentationen om JavaScript-grupper.

Efter att nyckeln har matchats konsumerar mönstret tilldelningens avgränsare en gång. Därefter väljer det antingen grenen för dubbla citattecken eller grenen för enkla citattecken. Varje gren godtar vanliga tecken, inklusive likhetstecken, eller ett omvänt snedstreck tillsammans med det efterföljande tecknet. Ett o-escapat matchande citattecken avslutar grenen.

Den här strukturen hanterar escapade citattecken utan att behandla dem som slutet på värdet. Den hanterar också parade omvända snedstreck: när ett par har konsumerats tillsammans kan ett efterföljande o-escapat citattecken avsluta strängen. Tomma värden fungerar eftersom innehållet inom citattecknen får upprepas noll gånger.

Programmet läser fångsterna via match[1] och match[2]. Ett misslyckat anrop till exec() returnerar null, enligt specifikationen för ECMAScripts RegExp.prototype.exec. Den extra längdjämförelsen kräver att matchningen täcker hela den fysiska raden.

Endast mellanslag och tabbar räknas som omgivande formatering. Programmet trimmar aldrig innehållet i ett värde. Därför behåller label = " Blue = Green " mellanslagen i båda ändarna av det citerade innehållet.

Varför använda en ersättningsfunktion vid omformatering?

Normaliseringssteget returnerar den fångade nyckeln, en standardiserad avgränsare och det fångade värdet. Ersättningsåteranropet får först hela matchningen, följd av de två fångsterna. JavaScript dokumenterar argumentens ordning i String.prototype.replace().

Texten som ett återanrop returnerar infogas ordagrant, utan att ersättningstoken som $1 eller $$ tolkas. Då förblir exempelvärdet "$1 = $$" intakt. Samma dokumentation förklarar skillnaden mellan ersättningssträngar och ersättningsfunktioner.

En fast ersättningsmall som "$1 = $2" skulle också fungera för det här specifika mönstret: fångat innehåll infogas utan ytterligare en substitutionsomgång. Återanropet blir särskilt användbart när ersättningstext skapas dynamiskt, eftersom det håller den returnerade texten åtskild från ersättningsmallens syntax.

Normaliseringen ändrar avsiktligt omgivande blanksteg och konverterar fysiska radslut till LF. Den bevarar tomma rader och den exakta citerade värdetexten. Om uppgiften kräver de ursprungliga blanktecknen och radsluten använder du de extraherade paren för granskning och låter den ursprungliga source vara oförändrad.

Vad bör du kontrollera innan du använder resultatet?

Extraheringsfunktionen samlar in fel med radnummer och kastar ett fel innan något av resultaten skrivs ut. Tomma rader som endast innehåller mellanslag eller tabbar ignoreras uttryckligen. En felaktigt formaterad rad som inte är tom kan därför inte försvinna i ett skenbart lyckat delresultat.

Använd de här syntetiska fallen för att diagnostisera oväntad indata:

Tilldelningstext Förväntat resultat
x="a=b=c" Bevara hela det citerade värdet.
x='' Godta ett tomt värde inom enkla citattecken.
x=" a=b " Bevara mellanslagen inuti citattecknen.
x="a\"=b" Bevara det escapade citattecknet och likhetstecknet.
x="a=b Rapportera det saknade avslutande citattecknet.
x="a" extra Rapportera efterföljande text.
x="a" y="b" Avvisa flera tilldelningar på samma rad.
x=a=b Avvisa ett ociterat värde enligt den här grammatiken.

Extraherings- och normaliseringslogiken i programmet kördes i Node.js 20.19.2 med det visade exemplet. Ytterligare femton deterministiska kontroller omfattade citerade likhetstecken, tomma värden, escapade citattecken, parade omvända snedstreck, bokstavliga dollarteckenstoken, felaktigt formaterade rader, dubblerade nycklar och hantering av tomma rader. Det verifierar den definierade omvandlingslogiken; det innebär inte att Safari-gränssnittet har testats.

Om en rad misslyckas kontrollerar du först avgränsarna och letar sedan efter ett avslutande omatchat omvänt snedstreck, efterföljande text eller en nyckel som inte stöds. Ändra grammatiken medvetet när uppgiften kräver mer syntax. För det angivna formatet med en tilldelning per rad blir resultatet ett återanvändbart par fält där det citerade värdet behåller alla interna likhetstecken.

Källor