Untuk mengekstrak penugasan seperti title = "Blue = Green", cocokkan kunci dan seluruh nilai yang dikutip secara bersamaan. Panduan Mac ini menggunakan JavaScript di Safari untuk mempertahankan tanda sama dengan, tanda kutip, dan garis miring terbalik di dalam nilai, sekaligus melaporkan baris yang formatnya salah.

Mengapa pemisahan berdasarkan tanda sama dengan menghilangkan bagian dari nilai?

Perhatikan penugasan sintetis berikut:

title = "Blue = Green"

Kunci yang dimaksud adalah title; nilainya, termasuk tanda kutip aslinya, adalah "Blue = Green". Hanya tanda sama dengan pertama yang memisahkan bidang. Tanda kedua merupakan bagian dari teks yang dikutip.

split("=") milik JavaScript memisahkan pada setiap kemunculan tanpa menafsirkan tanda kutip. Menambahkan batas, seperti pada split("=", 2), memotong array yang dihasilkan; cara itu tidak mempertahankan semua teks setelah pemisah pertama. Hal ini sesuai dengan definisi standar String.prototype.split.

Metode yang tepat bergantung pada tata bahasa masukan. Gunakan panduan keputusan ini sebelum mengubah teks:

Kondisi masukan Pendekatan yang sesuai
Satu penugasan per baris; hanya perlu pemisahan Temukan tanda sama dengan pertama dan pertahankan seluruh sisanya.
Satu penugasan per baris; sintaks tanda kutip dan kunci juga harus diperiksa Cocokkan seluruh baris dengan pola penugasan yang ditentukan, seperti di bawah.
Beberapa penugasan per baris atau nilai yang mencakup beberapa baris Gunakan pengurai yang dirancang untuk aturan tambahan tersebut.

Untuk tugas ini, validasi seluruh baris memberikan pemeriksaan tambahan yang berguna: tanda kutip yang tidak berpasangan atau teks tambahan yang tidak terduga akan menghasilkan kesalahan, bukan ekstraksi yang tidak lengkap.

Tata bahasa penugasan apa yang dipertahankan oleh contoh ini?

Program di bawah menerapkan format teks yang sengaja dibuat sederhana. Aturan berikut adalah aturan yang ditetapkan di sini, bukan klaim bahwa program ini mengurai semua penugasan JavaScript:

  • Setiap baris yang tidak kosong memuat satu penugasan.
  • Kunci diawali huruf ASCII atau garis bawah, lalu diikuti huruf ASCII, angka, atau garis bawah.
  • Nilai menggunakan tanda kutip lurus tunggal atau ganda yang berpasangan. Nilai bertanda kutip kosong valid.
  • Di dalam nilai, garis miring terbalik berpasangan dengan karakter berikutnya, kecuali karakter carriage return atau baris baru. Kedua karakter tetap tidak berubah.
  • Spasi dan tab boleh mengapit kunci, pemisah, dan nilai. Spasi dan tab di dalam tanda kutip tetap menjadi bagian dari nilai.
  • Akhir baris fisik boleh berupa LF, CRLF, atau CR. Nilai yang dikutip tidak boleh melintasi akhir baris tersebut.
  • Komentar, titik koma, dan nilai tanpa tanda kutip tidak termasuk dalam tata bahasa ini.

Sebagai contoh, caption='Small = calm' valid. note="Use \"a=b\" here" juga valid: tanda kutip ganda yang di-escape merupakan bagian dari nilai. Sebaliknya, caption='Small = calm" memiliki pembatas yang tidak berpasangan dan harus diperbaiki.

Keluaran menyimpan setiap nilai sebagai rawValue, termasuk tanda kutip pembatasnya. Ekstraksi tidak menguraikan urutan escape: dua karakter \n tetap menjadi dua karakter. Dengan demikian, hasilnya dapat digunakan untuk menyusun ulang teks penugasan tanpa mengubah representasi tertulisnya.

Kunci duplikat juga tetap menjadi entri terpisah dalam urutan aslinya. Pilihan ini mencegah nilai sebelumnya tergantikan secara diam-diam saat kunci yang sama muncul lagi.

Bagaimana menjalankan transformasi di Safari pada Mac?

Web Inspector Safari menyediakan tempat untuk menjalankan JavaScript. Aktifkan melalui Safari → Settings… → Advanced → Show features for web developers. Kemudian pilih Develop → Show Web Inspector, atau tekan Option-Command-I. Langkah-langkah ini didokumentasikan dalam Mengaktifkan Web Inspector dari WebKit.

Pilih tab Console dan gunakan kolom masukan untuk seluruh program di bawah. WebKit mendokumentasikan kolom tersebut sebagai tempat untuk mengevaluasi JavaScript dalam Referensi Antarmuka Web Inspector. Contoh ini hanya beroperasi pada string yang ditulis di dalam program.

Contoh ini menggunakan String.raw agar garis miring terbalik tetap utuh saat string JavaScript dibuat. Saat mengedit contoh, ingat bahwa tanda backtick dan ${...} tetap memiliki makna khusus dalam literal templat; masukan ini tidak memuat keduanya. Baca dokumentasi JavaScript String.raw() sebelum menambahkan karakter tersebut.

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

Ini adalah program lengkap dengan data contoh dan tanpa impor atau paket tambahan. Fungsi pembungkusnya menjaga deklarasi tetap lokal, sehingga seluruh contoh dapat dijalankan kembali setelah data contoh diedit.

Pesan konsol pertama memisahkan bidang:

key: title
value: "Blue = Green"

key: caption
value: 'Small = calm'

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

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

key: empty
value: ""

Pesan kedua menampilkan penugasan dengan spasi yang seragam:

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

Pilih dan salin blok teks yang sesuai dengan tugas desktop. Program menampilkan hasil melalui console.log, yang didokumentasikan WebKit dalam API Objek Console. Program ini tidak menulis berkas.

Bagaimana pola ini mempertahankan tanda sama dengan di dalam nilai yang dikutip?

Pola ini memiliki dua grup tangkapan: satu untuk kunci dan satu untuk seluruh nilai yang dikutip. (?:...) di dalamnya mengelompokkan alternatif tanpa membuat bidang tangkapan tambahan. Penggunaan grup tangkapan dan non-tangkapan ini sesuai dengan dokumentasi grup JavaScript.

Setelah mencocokkan kunci, pola ini mengonsumsi pemisah penugasan satu kali. Lalu pola memilih cabang bertanda kutip ganda atau cabang bertanda kutip tunggal. Setiap cabang menerima karakter biasa, termasuk tanda sama dengan, atau garis miring terbalik yang berpasangan dengan karakter berikutnya. Tanda kutip yang cocok dan tidak di-escape menutup cabang tersebut.

Struktur ini menangani tanda kutip yang di-escape tanpa menganggapnya sebagai akhir nilai. Struktur ini juga menangani garis miring terbalik yang berpasangan: setelah sepasang karakter dikonsumsi bersama, tanda kutip berikutnya yang tidak di-escape dapat menutup string. Nilai kosong juga berfungsi karena isi yang dikutip boleh berulang sebanyak nol kali.

Program membaca tangkapan melalui match[1] dan match[2]. Pemanggilan exec() yang gagal menghasilkan null, sebagaimana ditentukan oleh ECMAScript RegExp.prototype.exec. Perbandingan panjang tambahan mengharuskan kecocokan mencakup seluruh baris fisik.

Hanya spasi dan tab yang dianggap sebagai pemformatan di sekitar nilai. Program tidak pernah memangkas bagian dalam nilai. Karena itu, label = " Blue = Green " mempertahankan kedua spasi di setiap ujung isi yang dikutip.

Mengapa menggunakan fungsi pengganti saat memformat ulang?

Langkah normalisasi mengembalikan kunci yang ditangkap, pemisah standar, dan nilai yang ditangkap. Fungsi callback pengganti menerima seluruh kecocokan terlebih dahulu, lalu kedua tangkapan. JavaScript mendokumentasikan urutan argumen ini dalam String.prototype.replace().

Teks yang dikembalikan callback disisipkan secara harfiah, tanpa menafsirkan token pengganti seperti $1 atau $$. Dengan begitu, nilai contoh "$1 = $$" tetap utuh. Dokumentasi yang sama menjelaskan perbedaan antara string pengganti dan fungsi pengganti.

Templat pengganti tetap seperti "$1 = $2" juga berfungsi untuk pola khusus ini: isi tangkapan disisipkan tanpa proses substitusi kedua. Callback sangat berguna saat menyusun teks pengganti secara dinamis karena nilai yang dikembalikan tetap terpisah dari sintaks templat pengganti.

Normalisasi sengaja mengubah spasi di sekitar nilai dan mengonversi akhir baris fisik menjadi LF. Normalisasi ini mempertahankan baris kosong dan teks nilai yang dikutip secara persis. Jika tugas mengharuskan spasi dan akhir baris asli tetap dipertahankan, gunakan pasangan yang diekstrak untuk pemeriksaan dan biarkan source asli tetap utuh.

Apa yang perlu diperiksa sebelum menggunakan hasilnya?

Fungsi ekstraksi mengumpulkan kesalahan beserta nomor barisnya dan melempar kesalahan sebelum salah satu hasil dicetak. Baris kosong yang hanya berisi spasi atau tab secara eksplisit diabaikan. Karena itu, baris tidak kosong yang formatnya salah tidak dapat hilang begitu saja dalam hasil parsial yang tampak berhasil.

Gunakan kasus sintetis berikut untuk mendiagnosis masukan yang tidak terduga:

Teks penugasan Hasil yang diharapkan
x="a=b=c" Pertahankan seluruh nilai yang dikutip.
x='' Terima nilai kosong bertanda kutip tunggal.
x=" a=b " Pertahankan spasi di dalam tanda kutip.
x="a\"=b" Pertahankan tanda kutip yang di-escape dan tanda sama dengan.
x="a=b Laporkan tanda kutip penutup yang hilang.
x="a" extra Laporkan teks tambahan di akhir.
x="a" y="b" Tolak beberapa penugasan pada satu baris.
x=a=b Tolak nilai tanpa tanda kutip menurut tata bahasa ini.

Logika ekstraksi dan normalisasi program dijalankan di Node.js 20.19.2 dengan contoh yang ditampilkan. Lima belas pemeriksaan deterministik tambahan mencakup tanda sama dengan dalam nilai yang dikutip, nilai kosong, tanda kutip yang di-escape, garis miring terbalik berpasangan, token dolar literal, baris yang formatnya salah, kunci duplikat, dan penanganan baris kosong. Ini memverifikasi logika transformasi yang ditetapkan; bukan klaim bahwa antarmuka Safari telah diuji.

Jika sebuah baris gagal, periksa dulu pembatasnya, lalu cari garis miring terbalik terakhir yang tidak berpasangan, teks tambahan, atau kunci yang tidak didukung. Ubah tata bahasanya dengan sengaja jika tugas memerlukan sintaks tambahan. Untuk format satu penugasan per baris yang dinyatakan, hasilnya berupa pasangan bidang yang dapat digunakan kembali, dengan nilai yang dikutip tetap mempertahankan semua tanda sama dengan di dalamnya.

Sumber