Я пытаюсь string.matchAll следующую строку:
const text = 'textA [aaa](bbb) textB [ccc](ddd) textC'
Я хочу сопоставить следующее:
"textA [aaa](bbb)"" textB [ccc](ddd)"" textC"ПРИМЕЧАНИЕ: Группы захвата уже присутствуют в regex. Это то что мне нужно.
Это почти работает, но до сих пор я не мог придумать, как сопоставить последнюю часть строки, которая представляет собой просто " textC" и не имеет шаблона [*](*).
Что я делаю неправильно?
const text = 'textA [aaa](bbb) textB [ccc](ddd) textC'
const regexp = /(.*?)\[(.+?)\]\((.+?)\)/g;
const array = Array.from(text.matchAll(regexp));
console.info(JSON.stringify(array[0][0]));
console.info(JSON.stringify(array[1][0]));
console.info(JSON.stringify(array[2][0]));Обновлено:
Помимо хороших решений, представленных в ответах ниже, это также вариант:
const text= 'textA [aaa](bbb) textB [ccc](ddd) textC'
const regexp = /(?!$)([^[]*)(?:\[(.*?)\]\((.*?)\))?/gm;
const array = Array.from(text.matchAll(regexp));
console.info(array);Что-то не так с (.+\)) (.+\)) (.+)?
textC заполнителем, и он может быть просто равен word 1 word 2 and word 3 and so on...., и вам нужно получить этот текст как один элемент в результирующем массиве?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Потому что третьего матча нет. После первых двух совпадений в строке остается только «текст C»:
https://regex101.com/r/H9Kn0G/1/
чтобы исправить это, сделайте всю вторую часть необязательной (также обратите внимание на начальную \w вместо ., чтобы эта точка не поглощала всю строку, а также скобки «только для группировки», используемые для окружения необязательной части, что сохраняет ваши группы соответствия тоже самое):
(\w+)(?:\s\[(.+?)\]\((.+?)\))?
https://regex101.com/r/Smo1y1/2/
Слово характер слишком ограничительно для меня. Я хочу сопоставить ЛЮБУЮ строку, за которой следует шаблон [+](+), и если несколько шаблонов [+](+) написаны вместе один за другим, я хочу сопоставить их 1 на 1.
чтобы сопоставить буквально все до следующей скобки, попробуйте следующее: ((?:(?!\[).)+)(?:\s?\[(.+?)\]\((.+?)\))?. regex101.com/r/HqbTpU/1 Я добавил «закаленный токен» с этим отрицательным прогнозом, очевидно, более сложным.
@ScottWeaver Пожалуйста, никогда не используйте закаленный жадный токен, когда вы ограничиваете . одним символом. (?:(?!\[).)+ (почти) = [^[]+. На самом деле это равно чему-то вроде [^[\n\r]+. Класс отрицательных символов работает намного быстрее.
да, это немного проще и работает так же. regex101.com/r/vMFKXH/1
Кроме того, ваше регулярное выражение легко сломать, если перед построением [...](...) стоят "отдельные" скобки.
каждое решение регулярного выражения легко сломать. требуемая надежность до OP - иногда регулярное выражение лучше, иногда требуются алгоритмические подходы.
Точное решение, которое мне нужно, это ([^[]*)(?:\[(.+?)\]\((.+?)\))? , но оно соответствует последней позиции как нулевая длина. Если я изменю его на ([^[]+)(?:\[(.+?)\]\((.+?)\))?, требуя, чтобы первая группа имела хотя бы 1 символ, я избавлюсь от совпадения последней позиции, но я не могу сопоставить несколько шаблонов второй группы, когда они вместе, как [+](+)[+](+)[+](+)... Любой простой способ получить избавиться от этой последней позиции нулевой длины?
Кажется, я нашел то, что мне нужно: (?!$)([^[]*)(?:\[(.*?)\]\((.*?)\))?
множественный [+](+)...N — это другая игра, верно? потому что тогда это произвольная длина, которая не может быть правильно захвачена в группы соответствия. (вы можете захватить всю последовательность, а затем выполнить еще один анализ)
Вы можете разделить, сопоставив шаблон и получив подстроки из предыдущего индекса до конца совпадения:
const text = 'textA [aaa](bbb) textB [ccc](ddd) textC'
const regexp = /\[[^\][]*\]\([^()]*\)/g;
let m, idx = 0, result=[];
while(m=regexp.exec(text)) {
result.push(text.substring(idx, m.index + m[0].length).trim());
idx = m.index + m[0].length;
}
if (idx < text.length) {
result.push(text.substring(idx, text.length).trim())
}
console.info(result);Примечание:
\[[^\][]*\]\([^()]*\) соответствует [, любым 0+ символам, кроме [ и ] (с [^\][]*), затем ](, затем 0+ символов, кроме ( и ) (с [^()]*), а затем ) (см. демонстрация регулярных выражений).trim() добавлен, чтобы избавиться от начальных/конечных пробелов (удалите, если не нужно).Идея состоит в том, чтобы сопоставить любые символы перед имеющимся у вас шаблоном, а затем сопоставить либо ваш шаблон, либо конец строки:
let result = text.match(/(?!$)(.*?)(?:\[(.*?)\]\((.*?)\)|$)/g);
Если в строке могут быть разрывы строк, замените . на [\s\S] или рассмотрите этот шаблон:
let result = text.match(/(?!$)([\s\S]*?)(?:\[([^\][]*)\]\(([^()]*)\)|$)/g);
См. демонстрация регулярных выражений.
Демонстрация JS:
const text = 'textA [aaa](bbb) textB [ccc](ddd) textC'
const regexp = /(?!$)(.*?)(?:\[(.*?)\]\((.*?)\)|$)/g;
const array = Array.from(text.matchAll(regexp));
console.info(JSON.stringify(array[0][0]));
console.info(JSON.stringify(array[1][0]));
console.info(JSON.stringify(array[2][0]));Сведения о регулярном выражении
(?!$) - не в конце строки(.*?) - Группа 1: любые символы 0+, кроме символов разрыва строки, как можно меньше (измените на [\s\S]*?, если могут быть разрывы строк, или добавьте модификатор s, поскольку вы нацелены на ECMAScript 2018)(?:\[(.*?)\]\((.*?)\)|$) - любой из двух вариантов:
\[(.*?)\]\((.*?)\) - [, группа 2: как можно меньше любых символов 0+, кроме символов разрыва строки, ](, группа 3: как можно меньше любых символов 0+, кроме символов разрыва строки, и )| - или$ - конец строки.Извините, я слишком долго давал отзыв. Ваш ответ кажется слишком рабочим (в нем отсутствуют некоторые пробелы из textB и textC), но моя главная проблема в том, что он показался мне не очень читаемым. Я бы хотел, чтобы лучше работать с regex и методом matchAll. Спасибо.
У меня есть этот regex, который в основном работает, но он соответствует совпадению нулевой длины в последней позиции. /([^\[]*)?(?:\[(.+?)\]\((.+?)\))?/gm
@ cbdev420 Итак, вы хотите использовать нечитаемое регулярное выражение? :) /(?=[\s\S])([\s\S]*?)(?:\[([^\][]*)\]\(([^()]*)\)|$)/g
Я думаю, что регулярное выражение, которое я получил сейчас, которое почти работает, довольно читабельно. ([^\[]*)?(?:\[(.+?)\]\((.+?)\))? В основном группа соответствует любому символу, кроме левой скобки [, если это возможно, то я стараюсь соответствовать шаблону [+](+). Но я согласен, что удобочитаемость — это точка зрения. Это действительно личное.
Могу ли я изменить текущее регулярное выражение, чтобы избавиться от последнего совпадения? Или нужно было идти совсем другим путем? Спасибо большое за вашу помощь.
@ cbdev420 Я добавил в ответ решение с фиксированным регулярным выражением. С двумя вариациями
Спасибо! Я все еще тестирую некоторые варианты, но ваш точно работает.
@cbdev420 (?=.) или (?!$) являются синонимами. См. этот мой ответ.
Это то, что я в итоге использовал:
const text= 'textA [aaa](bbb) textB [ccc](ddd) textC'
const regexp = /(?!$)([^[]*)(?:\[(.*?)\]\((.*?)\))?/gm;
const array = Array.from(text.matchAll(regexp));
console.info(array);
попробуйте это: (\w+)\s*(?:[(.+?)]((.+?)))?