Захват пар ключ/значение объектной строки (аналогично JSON) с использованием регулярного выражения

С помощью такой строки, как {float: 'null', another: 'foo'}, я хотел бы получить каждый набор пар ключ/значение, чтобы группы выводили float, null, а также another и foo. Мое текущее регулярное выражение: /\{(?<set>(?<key>\w*)\s*\:\s*(?<value>.*)?\s?)*\}/g Он правильно захватывает ключ, но все, что находится после запятой, получает его как значение. Я использую именованные группы главным образом просто для ясности. Не могу понять, как извлечь каждую пару ключ/значение, особенно если их несколько. Спасибо за любую помощь

В настоящее время пытаюсь /\{(?<set>(?<key>\w*)\s*\:\s*(?<value>.*)?\s?)*\}/g, но результат:

группа «набор»: float: 'null', another: 'foo' (правильно)

группа «ключ»: float (правильно)

значение группы: 'null', another: 'foo' (неверно, я хочу просто null)

Хотелось бы, чтобы он захватывал все пары ключ/значение, если это возможно.


Измените для большей ясности:

Мой конкретный вариант использования — анализ Markdown и подключение его к пользовательским компонентам в Svelte, где я хочу контролировать возможность сбора реквизитов из синтаксиса markdown на изображении. Судя по тому, что я собрал в Интернете о присвоении атрибутов изображению, оно должно выглядеть примерно так:

![Alt Text]https://<fullurl>.jpg "This is hover text"){prop1: 'foo', prop2: 'bar', float: true}

Причиной регулярного выражения является анализ строки уценки. Это не JSON, и я ничего не получу, следуя семантике JSON (" на ключе)

попробуйте включить разделитель для set и key. Если вы уверены, что это слово, вы можете использовать \w+ или использовать ', чтобы закончить строку.

whereo 29.04.2024 08:35

Это не «похоже на JSON», это JSON. Я думаю, что лучшим подходом было бы просто использовать JSON.parse(), а затем заменить все 'null' на null. При необходимости вы можете использовать Object.entries() для результата.

Peter B 29.04.2024 08:38

Зачем использовать регулярное выражение? У вас уже есть пары «ключ-значение» в вашем объекте?

Wimanicesir 29.04.2024 08:59

@Peter B: разве json не должен использовать только двойные кавычки? И вокруг значений ("foo", а не 'foo'), и имен полей ("another", а не another)? (Я никогда даже не читал спецификацию json. Так что не уверен на 100%. Но я знаю, что мне часто приходилось заменять кавычки двойными кавычками, чтобы избежать ошибок, как в Python, так и в JS Firefox. Так что на практике использование парсеров json не помогло бы. не работаю с такой строкой)

chrslg 29.04.2024 15:16

Конечно, это не меняет того факта, что было бы гораздо разумнее использовать существующий формат с существующим парсером, чем пытаться заново изобрести колесо с помощью регулярных выражений и, вступая в бесконечный цикл, «наткнуться на случай, когда это не так». t работает → восстановить регулярное выражение "

chrslg 29.04.2024 15:18

@chrslg Упс, ты действительно на 100% прав. Так что на самом деле это не JSON.... Мои извинения всем.

Peter B 29.04.2024 15:43

На самом деле это похоже на объект javascript. (Можно сказать, нотация объекта JavaScript. Но не нотация объекта JavaScript). Но я бы, конечно, не посмел произнести это слово eval, это было бы зло :D

chrslg 29.04.2024 15:57

Добавил правку для большей ясности. То, что кажется объектом, является частью синтаксиса уценки, который я пытаюсь проанализировать; это строка. Возможно, я могу просто использовать JSON.parse() для всего совпадения, поскольку у меня есть доступ ко всему совпадению, хотя было бы неплохо не требовать ' или " для ключей.

KyleFontenot 29.04.2024 16:42

@chrslg, мне просто нравится твое сопоставление eval() и «зла». Я бы тоже никогда, никогда, никогда... не мечтал произнести такое слово. 🤣 Тем более не здесь! Гораздо лучше изобрести велосипед и написать еще один парсер. 😉

Carsten Massmann 29.04.2024 19:27

Прежде всего исправьте входную строку. Вы не можете ожидать, что 'null' не даст вам ложных срабатываний. Что, если вдруг кто-то действительно захочет передать строку «null»? Не следует конвертировать его в примитив. Вместо этого не заключайте его в кавычки.

Roko C. Buljan 29.04.2024 20:13
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
10
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Попробуйте использовать это длинное регулярное выражение JavaScript:

/(?<key>\w*)\s*:\s*(?<value>(?<quote>["'])(?:\\.|.)*?\k<quote>|(?<number>[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)|(?<constant>true|false|null))/g

В действии (посмотрите на всю страницу, если нет, то не все видно):

const regexKeyValue = /(?<key>\w*)\s*:\s*(?<value>(?<quote>["'])(?:\\.|.)*?\k<quote>|(?<number>[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)|(?<constant>true|false|null))/g;

document.getElementById('search').addEventListener('click', function () {
  const input = document.getElementById('input').value;

  let match,
      i = 1,
      output = [];

  while ((match = regexKeyValue.exec(input)) !== null) {
    console.info(`Match n°${i} : ` + match[0]);
    console.info('match.groups =', match.groups);

    // If the value is starting with quotes, then unquoted it and
    // also replace all the escape sequences (ex: "\\n" should become "\n").
    let value = match.groups.value;
    // If it's double quotes, let's use JSON.parse() as it will handle everything.
    if (value.match(/^"/)) {
      value = JSON.parse(value);
    }
    // If it's simple quotes, we can't use JSON.parse() so we have to convert
    // it to a double-quoted string before.
    else if (value.match(/^'/)) {
      value = value
        // 1) Remove the simple quotes around.
        .replace(/^'|'$/g, '')
        // 2) Replace all \' by '.
        // We have to search for all backslashes to handle also an escaped backslash.
        .replace(/\\(.)/g, function (fullMatch, afterBackslash) {
          if (afterBackslash === "'") {
            return "'";
          } else {
            return fullMatch;
          }
        })
        // 3) Escape all double quotes (" becomes \").
        .replace(/"/g, '\\"');
      // 4) Now use JSON.parse();
      value = JSON.parse(`"${value}"`);
    }
    
    // If it's a number or a constant, then convert the string to this real JS value.
    if (typeof match.groups.number !== 'undefined' ||
        typeof match.groups.constant !== 'undefined') {
      value = JSON.parse(match.groups.value);
    }

    console.info('value =', value);
    
    output.push(
      `Match n°${i++} :\n` +
      `  Key   : ${match.groups.key}\n` +
      `  Value : ${value}\n`
    );
  }

  document.getElementById('output').innerText = output.join("\n");
  document.getElementById('label').classList.remove('hidden');
});
textarea {
  box-sizing: border-box;
  width: 100%;
}

pre {
  overflow-y: scroll;
}

.hidden {
  display: none;
}
<textarea id = "input" rows = "10">{
  float: 'null',
  another: "foo",
  age: 45,
  type: '"simple" \' quote',
  comment: "Hello,\nA backslash \\, a tab \t and a \"dummy\" word.\nOk?",
  important: true,
  weight: 69.7,
  negative: -2.5
}</textarea>

<button id = "search">Search for key-value pairs</button>

<p id = "label" class = "hidden">Matches:</p>
<pre><code id = "output"></code></pre>

То же регулярное выражение, с комментариями, с флагом x PCRE предлагает:

/
(?<key>\w*)        # The key.
\s*:\s*            # : with optional spaces around.
(?<value>          # The value.
  # A string value, single or double-quoted:
  (?<quote>["'])   # Capture the double or single quote.
    (?:\\.|.)*?    # Backslash followed by anything or any char, ungreedy.
  \k<quote>        # The double or single quote captured before.
|
  # Int and float numbers:
  (?<number>[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)
|
  # true, false and null (or other constants):
  (?<constant>true | false | null)
)
/gx

Или, что еще лучше, в регулярном выражении 101 у вас будут цвета и объяснение. в правой колонке: https://regex101.com/r/bBPvUd/2

Это чертовски кратко, и мне нравится то, что вы сделали с обратной ссылкой на строку, чтобы обеспечить правильное окружение. Я собираюсь использовать ваш ответ, но не могу понять, как захватить строку только без кавычек. Как бы вы это сделали?

KyleFontenot 14.05.2024 16:38

Ну, как я это сделал, используя код JavaScript в своем ответе, используя JSON.parse(). Это потому, что мы хотим, чтобы \n был символом возврата каретки, а не обратной косой чертой, за которой следовал символ n. Но если вы хотите быстро захватить содержимое в регулярном выражении, просто добавьте группу захвата между кавычками, но имейте в виду, что захваченное содержимое не является окончательным желаемым значением, поскольку оно не будет оценено как правильная строка. .

Patrick Janser 14.05.2024 16:56

Как уже упоминалось в комментариях, eval() считается «злым» или, по крайней мере, небезопасным. Я точно забыл почему, что-то связано с межсайтовым скриптингом. Однако, если он используется в «безопасной» среде, т.е. е. для предварительной обработки ввода, над которой вы имеете полный контроль, тем не менее, это может быть допустимо.

const md=`Some text and now the image: 
![Alt Text]https://<fullurl>.jpg "This is hover text"){prop1: 'foo', prop2: 'bar', float: true} 
and some more text.

A new paragraph any yet nother picture
![Alt Text2]https://<fullerURL>.jpg "This is another hover text"){prop1: 'fool', prop2: 'bart', float: false} and this is the end.`;

function unsafeParse(s){
 return s.match(/\{[^}]+\}/g).map(t=>eval(`(${t})`));
}

// ouputs an array of all image property objects:
console.info(unsafeParse(md));

Помимо того, что вышеизложенное является «небезопасным», оно не является полностью отказоустойчивым, поскольку значения свойств, содержащие символ «}», вызовут проблемы...

Другие вопросы по теме

Похожие вопросы

Нужно ли мне возвращать что-то важное из случаев переключения или этого достаточно, чтобы различать разные PHP?
Как исправить данные, которые не отображаются на странице, но отображаются при предварительном просмотре в сети
Преобразовать список массивов внутри объекта в элементы div, содержащие до четырех элементов в React
Пользовательский клик передается только один раз в JavaScript вместе с другим поведением
Vue Quill css применяется только к моему первому компоненту Quill Editor + как настроить панель инструментов
Ошибка Alpine.js «paginationData не определена» в компоненте Laravel Jetstream
Показывать всплывающее окно разрешения для буфера обмена
Загрузка изображений React, повторная отрисовка загруженных изображений при добавлении/удалении
Элемент не обновляется в DOM после изменения его состояния реакции
Невозможно выполнить CRUD (операцию DELETE) в MongoDB (стек MERN)