Для извлечения присваиваний, таких как title = "Blue = Green", сопоставьте ключ и полное значение в кавычках вместе. Это руководство для Mac использует JavaScript в Safari для сохранения внутренних знаков равенства, кавычек и обратных слешей при сообщении о некорректных строках.

Почему разделение по знакам равенства теряет значение?

Рассмотрим это синтетическое присваивание:

title = "Blue = Green"

Предназначенный ключ — title; значение, включая его исходные кавычки, — "Blue = Green". Только первый знак равенства разделяет поля. Второй принадлежит тексту в кавычках.

Метод JavaScript split("=") делит при каждом вхождении без интерпретации кавычек. Добавление ограничения, как в split("=", 2), усекает полученный массив; оно не сохраняет всё после первого разделителя. Это соответствует определению String.prototype.split в стандарте.

Правильный метод зависит от грамматики входных данных. Используйте эту помощь в выборе перед изменением текста:

Условие входных данных Подходящий подход
Одно присваивание на строку; важно только разделение Найдите первый знак равенства и сохраните весь остаток.
Одно присваивание на строку; синтаксис кавычек и ключа также должны проверяться Сопоставьте всю строку с заданным шаблоном присваивания, как показано ниже.
Несколько присваиваний на строке или значения, охватывающие строки Используйте парсер, предназначенный для этих дополнительных правил.

Для этой задачи проверка всей строки даёт полезную дополнительную гарантию: несовпадающая кавычка или неожиданный хвостовой текст выдают ошибку вместо неполного извлечения.

Какую грамматику присваивания сохраняет этот пример?

Программа ниже реализует намеренно небольшой текстовый формат. Это его авторские правила, а не утверждение, что он разбирает любое присваивание JavaScript:

  • Каждая непустая строка содержит одно присваивание.
  • Ключи начинаются с буквы ASCII или подчёркивания, за которыми следуют буквы ASCII, цифры или подчёркивания.
  • Значения используют соответствующие прямые одинарные или прямые двойные кавычки. Пустые значения в кавычках допустимы.
  • Внутри значения обратный слеш объединяется со следующим символом, кроме возврата каретки или перевода строки. Оба символа остаются неизменными.
  • Пробелы и табуляция могут окружать ключ, разделитель и значение. Пробелы и табуляция внутри кавычек остаются частью значения.
  • Физические окончания строк могут быть LF, CRLF или CR. Значения в кавычках не могут переходить через эти окончания строк.
  • Комментарии, точки с запятой и значения без кавычек находятся вне этой грамматики.

Например, caption='Small = calm' допустим. Так же note="Use \"a=b\" here": экранированные двойные кавычки принадлежат значению. Напротив, caption='Small = calm" имеет несовпадающие разделители и должен быть исправлен.

Результат сохраняет каждое значение как rawValue, включая его обрамляющие кавычки. Извлечение не декодирует escape-последовательности: два символа \n остаются двумя символами. Это делает результат подходящим для переупорядочивания текста присваиваний без изменения его письменного представления.

Дублирующиеся ключи также остаются отдельными записями в исходном порядке. Этот выбор избегает молчательной замены более раннего значения при повторном появлении того же ключа.

Как запустить преобразование в Safari на Mac?

Веб-инспектор Safari предоставляет место для выполнения JavaScript. Включите его через Safari → Настройки… → Дополнительно → Показывать функции для веб-разработчиков. Затем выберите Разработка → Показать веб-инспектор или нажмите Option-Command-I. Эти шаги описаны в документе WebKit Enabling Web Inspector.

Выберите вкладку Console и используйте её поле ввода для полной программы ниже. WebKit описывает это поле как поле ввода для оценки JavaScript в своём справочнике по интерфейсу веб-инспектора. Пример работает только со строкой автора внутри программы.

Образец использует String.raw, чтобы его обратные слеши выжили при построении строки JavaScript. При редактировании образца помните, что обратные кавычки и ${...} всё ещё имеют значение шаблонных литералов; этот ввод не содержит ни тех, ни других. См. документацию по String.raw() JavaScript перед добавлением этих символов.

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

Это полная программа с примером данных и без импортов или дополнительных пакетов. Её обёртывающая функция сохраняет объявления локальными, позволяя запускать весь пример снова после редактирования образца.

Первое сообщение консоли разделяет поля:

key: title
value: "Blue = Green"

key: caption
value: 'Small = calm'

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

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

key: empty
value: ""

Второе сообщение предоставляет присваивания с единообразными пробелами:

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

Выберите и скопируйте тот текстовый блок, который подходит для настольной задачи. Программа отображает результаты через console.log, который WebKit описывает в своём API объекта Console. Она не записывает файл.

Как шаблон сохраняет знаки равенства в кавычках целыми?

Шаблон имеет две захватывающие группы: одну для ключа и одну для полного значения в кавычках. Его внутренние группы (?:...) организуют альтернативы без создания дополнительных захватываемых полей. Это использование захватывающих и не захватывающих групп соответствует документации по группам JavaScript.

После совпадения с ключом шаблон потребляет разделитель присваивания один раз. Затем он выбирает либо ветку с двойными кавычками, либо ветку с одинарными. Каждая ветка принимает обычные символы — включая знаки равенства — или обратный слеш, объединённый со следующим символом. Неэкранированная соответствующая кавычка закрывает эту ветку.

Эта структура обрабатывает экранированные кавычки, не считая их концом значения. Она также обрабатывает парные обратные слеши: после того как пара потребляется вместе, следующая неэкранированная кавычка может закрыть строку. Пустые значения работают, потому что содержимое в кавычках может повторяться ноль раз.

Программа считывает захваты через match[1] и match[2]. Неудачный вызов exec() возвращает null, как указано в ECMAScript RegExp.prototype.exec. Дополнительное сравнение длины требует, чтобы совпадение покрывало всю физическую строку целиком.

Только пробелы и табуляция считаются окружающим форматированием. Программа никогда не обрезает внутреннюю часть значения. Следовательно, label = " Blue = Green " сохраняет оба пробела на каждом конце содержимого в кавычках.

Зачем использовать функцию замены при переформатировании?

Шаг нормализации возвращает захваченный ключ, стандартизированный разделитель и захваченное значение. Её функция обратного вызова получает полное совпадение первым, за которым следуют два захвата. JavaScript описывает этот порядок аргументов в String.prototype.replace().

Возвращённый функцией обратного вызова текст вставляется буквально, без интерпретации маркеров замены, таких как $1 или $$. Это сохраняет образцовое значение "$1 = $$" целым. Та же документация объясняет это различие между строками замены и функциями замены.

Фиксированный шаблон замены, такой как "$1 = $2", также сработал бы для этого конкретного шаблона: захваченное содержимое вставляется без второго прохода подстановки. Функция обратного вызова становится особенно полезной при динамической сборке текста замены, потому что она hält возвращаемое значение отдельным от синтаксиса шаблона замены.

Нормализация намеренно меняет окружающие пробелы и преобразует физические окончания строк в LF. Она сохраняет пустые строки и точный текст значения в кавычках. Если задача требует исходных пробелов и окончаний строк, используйте извлечённые пары для проверки и сохраните исходный source без изменений.

Что нужно проверить перед использованием результата?

Функция извлечения собирает ошибки с номерами строк и выбрасывает их перед выводом любого результата. Пустые строки, содержащие только пробелы или табуляцию, явно игнорируются. Некорректная непустая строка поэтому не может исчезнуть в видимо успешном частичном результате.

Используйте эти синтетические случаи для диагностики неожиданного ввода:

Текст присваивания Ожидаемый результат
x="a=b=c" Сохранить всё значение в кавычках.
x='' Принять пустое значение в одинарных кавычках.
x=" a=b " Сохранить пробелы внутри кавычек.
x="a\"=b" Сохранить экранированную кавычку и знак равенства.
x="a=b Сообщить об отсутствующей закрывающей кавычке.
x="a" extra Сообщить о хвостовом тексте.
x="a" y="b" Отклонить несколько присваиваний на одной строке.
x=a=b Отклонить значение без кавычек по этой грамматике.

Логика извлечения и нормализации программы выполнялась в Node.js 20.19.2 с показанным образцом. Пятнадцать дополнительных детерминированных проверок охватили знаки равенства в кавычках, пустые значения, экранированные кавычки, парные обратные слеши, буквальные токены доллара, некорректные строки, дублирующиеся ключи и обработку пустых строк. Это проверяет авторскую логику преобразования; это не утверждение о том, что интерфейс Safari был опробован.

Если строка не проходит, сначала проверьте её разделители, затем поищите последний непарный обратный слеш, хвостовой текст или неподдерживаемый ключ. Измените грамматику намеренно, когда задаче нужен более широкий синтаксис. Для указанного формата с одним присваиванием на строку результатом является повторно используемая пара полей, чьё значение в кавычках сохраняет каждый внутренний знак равенства.

Источники