Модифицируйте шаблон регулярных выражений для захвата вложенных тегов в массив объектов. - PullRequest
0 голосов
/ 19 марта 2019

Я пытаюсь создать шаблон регулярного выражения для соответствия тегам "faux" html для небольшого приложения, которое я создаю.

Я создал регулярное выражение для захвата найденных совпадений в {tag}brackets{/tag} и вывода их в массив объектов, таких как:

{
  {key : value}, 
  {key : value}
}

Код с текущим шаблоном:

let str = "{p}This is a paragraph{/p} {img}(path/to/image) {ul}{li}This is a list item{/li}{li}Another list item{/li}{/ul}";

let regex = /\{(\w+)}(?:\()?([^\{\)]+)(?:\{\/1})?/g;
let match;
let matches = [];

while (match = regex.exec(str)) {
    matches.push({ [match[1]]: match[2]})
}

console.log(matches)

Ссылка на JSbin

Я понял, что мне нужен также шаблон для захвата вложенных групп и помещения их в массив- так что результат для вышеупомянутого string будет:

[
  {p : "This is a paragraph"},
  {img : "path/to/image"},
  {ul : ["This is a list item", "Another List item"]}
]

Идея здесь состоит в том, чтобы сопоставлять каждый тег по порядку, чтобы индексы массива соответствовали порядку, в котором они были найдены (т.е. первый абзацв приведенной выше строке есть array[0] и т. д.).

Если у кого-то есть немного информации о том, как я мог бы структурировать шаблон, это было бы очень полезно.У меня не будет более 1 уровня глубокого вложения, если это что-то изменит.

Я могу использовать другую разметку для ul, если это поможет, однако я не могу использовать квадратные скобки [text] из-за конфликтов с другой функцией, которая генерирует текст, который я пытаюсь извлечь в этомшаг.

Редактировать: Идея, которая меня поразила, состоит в том, чтобы иметь третью группу захвата для захвата и передачи в список-массив, но я не уверен, сработает ли это на самом деле?Я до сих пор не заставил его работать

1 Ответ

0 голосов
/ 19 марта 2019

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

Однако я бы выбрал другое решение:

Вы можете положиться на DOMParser - доступно в браузерах, или, если вы находитесь на Node, аналогичная функциональность доступна в нескольких модулях.

Чтобы использовать его, вам нужно иметь строку в формате XML, поэтому, если вы не хотите использовать теги в стиле <p>, вам сначала нужно преобразовать в нее строку, убедившись, что содержимое с < будет нужно получить &lt; вместо этого.

Также тегу {img} потребуется получить закрывающий тег вместо скобок. Таким образом, замена необходима для этого конкретного случая.

Как только это выйдет из-под контроля, довольно просто получить DOM из этого XML, который, возможно, уже достаточно хорош для вашей работы, но его можно упростить до желаемой структуры с помощью простой рекурсивной функции:

const str = "{p}This is a paragraph{/p} {img}(path/to/image) {ul}{li}This is a list item{/li}{li}Another list item{/li}{/ul}";

const xml = str.replace(/\{img\}\((.*?)\)/g, "{img}$1{/img}") 
               .replace(/</g, "&lt;")
               .replace(/\{/g, "<").replace(/\}/g, ">");
const parser = new DOMParser();
const dom = parser.parseFromString("<root>" + xml + "</root>", "application/xml").firstChild;
const parse = dom => dom.nodeType === 3 ? dom.nodeValue.trim() : {
    [dom.nodeName]: dom.children.length
                ? Array.from(dom.childNodes, parse).filter(Boolean)
                : dom.firstChild.nodeValue
};
const result = parse(dom).root;
console.log(result);

Вывод почти соответствует вашим ожиданиям, за исключением того, что элементы li также представлены как { li: "...." } объекты.

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