Регулярное выражение с игнорированием символа в кавычках
Здравствуйте. Прошу помочь мне в составлении регулярного выражения (или сообщить, если решение этой задачи невозможно в рамках регулярных выражений JS).
Задача: нужно распарсить код, по структуре похожий на HTML. Пример: <tag1 name1="value1" name2 = 'value2'> < tag1 name1="value1"name2 = 'value2' > Наличие и расположение пробелов может быть произвольным. Кавычки могут быть одинарными или двойными. Требуется: выбрать весь тег, начиная с открывающего символа < и заканчивая закрывающим > включительно. Задача осложняется тем, что значения, заключенные в кавычки, могут содержать символы < и >. Следовательно, выражение типа /<\s*tag1([^>]*)>/gi Не подходит. Можно ли как-нибудь выбрать текст до первого не заключенного в кавычки (одинарные или двойные) символа > при помощи регулярного выражения, или нужно писать парсер с логическим анализом? |
Tachyon,
вариант... let str = `<tag1 name1="value1" name2 = 'value>>>>><<<2'> < tag1 name1="value1"name2 = 'value2<<>>>' >`; let reg = /<\s*?\S+((['"])[^'"]*\2|[^>])*>/gi; console.log(str.match(reg)) |
Подправил маленько
let str = `<tag1 name1="<value1's>" name2 = 'value>>>>><<<2'> < tag1 name1="value1"name2 = 'value2<<>>>' >`; let reg = /<\s*?\S+((['"]).*?\2|[^>])*>/gi; console.log(str.match(reg)) |
Представленные варианты ошибочно срабатывают на
str = `<tag2 c="" d=">`; и, что самое грустное, безбожно зависают на длинном незакрытом теге str = `<tag1 b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""b=""`; Вот такое вроде бы нигде не косячит: let str = `<tag1 name1="<value1's>" name2 = 'value>>>>><<<2'> < tag1 name1="value1"name2 = 'value2<<>>>' >`; let reg = /<\s*\w+(?:"[^"]*"|'[^']*'|[^>"'])*>/gi; console.log(str.match(reg)); |
Большое спасибо! Немного усложнил последний вариант (на случай отсутствия параметров в теге) и погонял его с разными комбинациями, которые смог придумать, вроде бы везде сработал корректно:
var string = `aaaa< tag1 name1=">><<" name2= "val'2"name3 = 'val><"3' name4 ='' >bbbb`; string = string.replace(/<\s*tag1(\s+(?:"[^"]*"|'[^']*'|[^>"'])*)?>/gi, function(a,b) { alert(b); return ''; } ); alert(string); Задам еще один вопрос. Я правильно понимаю, что в регулярных выражениях JS отсутствует опережающая проверка, и из-за этого обработку тегов типа <tag1 name='value'>string'"test<>continue</tag1> с выбором строки не до символа, а до слова /<\s*\/\s*tag1\s*>/ регулярным выражением не сделать? |
Цитата:
Код:
<tag1""""""""""""""""""/> Цитата:
Код:
<tag1""""""""""""""""""/> Цитата:
/<\s*tag1(?:\s*[^\s=>]+\s*=\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"))*\s*>/giКак оно выглядит? |
Цитата:
Чтобы парсить полученную строку с параметрами я составил вот такой regexp, вроде бы делает именно то, что надо: /\s*([\w-]+)\s*[=:]\s*("[^"]*"|'[^']*'|[\w-]+)\s*/g Единственный недостаток - могут встречаться ключи без значения. Типа <tag1 name='value' clear> Подразумевается, что clear=true. Но ретроспективные и опережающие проверки на IE 11 и FF 56, видимо, совсем не работают. Так что я сделаю replace по предыдущему выражению, чтобы удалило из строки все найденные пары ключ=значение, а что останется - буду уже парсить отдельно. |
Цитата:
Цитата:
/<\s*tag1(?:\s*(?:[\w-]+)\s*(?:[:=]\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"|[\w-]+))?)*\s*>/giКак это выглядит? |
Цитата:
Цитата:
Немного пофиксил, на этот раз вроде всё как надо :) /<\s*tag1(?:\s+(?:[\w-]+(?![\w-])(?:\s*[:=]\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"|[\w-]+))?\s*)+)?\s*>/gi |
Alexandroppolus, замечательно!
Tachyon, меня интересует, почему всё-таки нужно такое? Почему бы не использовать XML? Тогда не нужно так мучаться... И всё нормально работает... включая комментарии! И парсеры уже есть! (в браузере даже есть готовый класс DOMParser) var code = ` <my-code> <tag1 name1="value1" name2="value2" /> <tag1 name1="value1" name2="value2" /> </my-code> `; var parser = new DOMParser(); var doc = parser.parseFromString(code, "text/xml"); // дальше работа с иерархией разобранных элементов console.log(doc); |
Часовой пояс GMT +3, время: 10:16. |