Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 19.06.2019, 15:53
Новичок на форуме
Отправить личное сообщение для Tachyon Посмотреть профиль Найти все сообщения от Tachyon
 
Регистрация: 19.06.2019
Сообщений: 8

Регулярное выражение с игнорированием символа в кавычках
Здравствуйте. Прошу помочь мне в составлении регулярного выражения (или сообщить, если решение этой задачи невозможно в рамках регулярных выражений JS).

Задача: нужно распарсить код, по структуре похожий на HTML. Пример:
<tag1 name1="value1" name2 = 'value2'>
< tag1 name1="value1"name2 = 'value2' >

Наличие и расположение пробелов может быть произвольным. Кавычки могут быть одинарными или двойными.

Требуется: выбрать весь тег, начиная с открывающего символа < и заканчивая закрывающим > включительно.

Задача осложняется тем, что значения, заключенные в кавычки, могут содержать символы < и >. Следовательно, выражение типа
/<\s*tag1([^>]*)>/gi

Не подходит.

Можно ли как-нибудь выбрать текст до первого не заключенного в кавычки (одинарные или двойные) символа > при помощи регулярного выражения, или нужно писать парсер с логическим анализом?

Последний раз редактировалось Tachyon, 19.06.2019 в 16:17.
Ответить с цитированием
  #2 (permalink)  
Старый 19.06.2019, 16:27
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,068

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))
Ответить с цитированием
  #3 (permalink)  
Старый 19.06.2019, 19:37
Аватар для Белый шум
Профессор
Отправить личное сообщение для Белый шум Посмотреть профиль Найти все сообщения от Белый шум
 
Регистрация: 19.01.2012
Сообщений: 498

Подправил маленько
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))
Ответить с цитированием
  #4 (permalink)  
Старый 19.06.2019, 21:17
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,005

Представленные варианты ошибочно срабатывают на
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));

Последний раз редактировалось Alexandroppolus, 20.06.2019 в 07:22.
Ответить с цитированием
  #5 (permalink)  
Старый 20.06.2019, 09:49
Новичок на форуме
Отправить личное сообщение для Tachyon Посмотреть профиль Найти все сообщения от Tachyon
 
Регистрация: 19.06.2019
Сообщений: 8

Большое спасибо! Немного усложнил последний вариант (на случай отсутствия параметров в теге) и погонял его с разными комбинациями, которые смог придумать, вроде бы везде сработал корректно:
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*>/ регулярным выражением не сделать?

Последний раз редактировалось Tachyon, 20.06.2019 в 10:47.
Ответить с цитированием
  #6 (permalink)  
Старый 20.06.2019, 16:24
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от Alexandroppolus
Вот такое вроде бы нигде не косячит:
А такое тоже должно подходить?
Код:
<tag1""""""""""""""""""/>
Сообщение от Tachyon
погонял его с разными комбинациями, которые смог придумать, вроде бы везде сработал корректно:
А такое тоже должно подходить?
Код:
<tag1""""""""""""""""""/>
<tag1 %ЭПОХА% @ВЫМЫСЛА@>
Сообщение от Tachyon
выбрать весь тег, начиная с открывающего символа < и заканчивая закрывающим > включительно.

Задача осложняется тем, что значения, заключенные в кавычки, могут содержать символы < и >.
/<\s*tag1(?:\s*[^\s=>]+\s*=\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"))*\s*>/gi
Как оно выглядит?
Ответить с цитированием
  #7 (permalink)  
Старый 20.06.2019, 17:23
Новичок на форуме
Отправить личное сообщение для Tachyon Посмотреть профиль Найти все сообщения от Tachyon
 
Регистрация: 19.06.2019
Сообщений: 8

Сообщение от Malleys Посмотреть сообщение
А такое тоже должно подходить?
По идее не должно. Должны быть только варианты имя=значение, или имя:значение. Вокруг = (или : ) могут быть пробелы. Значение может быть в одинарных или двойных кавычках, может быть без кавычек, если не содержит пробелов и других не буквенно-цифровых символов.

Чтобы парсить полученную строку с параметрами я составил вот такой regexp, вроде бы делает именно то, что надо:
/\s*([\w-]+)\s*[=:]\s*("[^"]*"|'[^']*'|[\w-]+)\s*/g


Единственный недостаток - могут встречаться ключи без значения. Типа <tag1 name='value' clear>
Подразумевается, что clear=true. Но ретроспективные и опережающие проверки на IE 11 и FF 56, видимо, совсем не работают. Так что я сделаю replace по предыдущему выражению, чтобы удалило из строки все найденные пары ключ=значение, а что останется - буду уже парсить отдельно.

Последний раз редактировалось Tachyon, 20.06.2019 в 17:37.
Ответить с цитированием
  #8 (permalink)  
Старый 20.06.2019, 17:51
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

Сообщение от Tachyon
Должны быть только варианты имя=значение, или имя:значение. Вокруг = (или : ) могут быть пробелы. Значение может быть в одинарных или двойных кавычках, может быть без кавычек, если не содержит пробелов и других не буквенно-цифровых символов.
Сообщение от Tachyon
могут встречаться ключи без значения. Типа <tag1 name='value' clear>
Можно так...

/<\s*tag1(?:\s*(?:[\w-]+)\s*(?:[:=]\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"|[\w-]+))?)*\s*>/gi
Как это выглядит?

Последний раз редактировалось Malleys, 20.06.2019 в 17:56.
Ответить с цитированием
  #9 (permalink)  
Старый 20.06.2019, 19:25
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,005

Сообщение от Tachyon
Задам еще один вопрос. Я правильно понимаю, что в регулярных выражениях JS отсутствует опережающая проверка, и из-за этого обработку тегов типа
<tag1 name='value'>string'"test<>continue</tag1>
с выбором строки не до символа, а до слова /<\s*\/\s*tag1\s*>/ регулярным выражением не сделать?
В принципе можно при определенных ограничениях, только регулярки охренительные будут. Вон для открывающего тега уже черт знает что пришлось нагородить А тут много всяких кейсов добавляется: это и вложенные теги, и подстрока "</tag1>" в атрибуте постороннего тега, а если ещё комментарии <!-- --> добавятся, то всё, приехали. Так что в общем случае надо лепить что-то вроде конечного автомата на регулярках и честно обходить всю строку целиком.

Сообщение от Malleys
Можно так...

/<\s*tag1(?:\s*(?:[\w-]+)\s*(?:(=)\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"|[\w-]+))?)*\s*>/gi
Та же засада с бэктрекингом для строки `<tag1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`


Немного пофиксил, на этот раз вроде всё как надо
/<\s*tag1(?:\s+(?:[\w-]+(?![\w-])(?:\s*[:=]\s*(?:'(?:\\\\|\\'|[^\\'])*'|"(?:\\\\|\\"|[^\\"])*"|[\w-]+))?\s*)+)?\s*>/gi
Ответить с цитированием
  #10 (permalink)  
Старый 20.06.2019, 21:02
Аватар для Malleys
Профессор
Отправить личное сообщение для Malleys Посмотреть профиль Найти все сообщения от Malleys
 
Регистрация: 20.12.2009
Сообщений: 1,714

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);

Последний раз редактировалось Malleys, 20.06.2019 в 21:10.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Регулярное выражение Medvedoc Firefox/Mozilla 2 08.11.2017 17:42
Регулярное выражение tata4ka Общие вопросы Javascript 4 15.11.2014 00:56
Регулярное выражение и метод test tsigel Общие вопросы Javascript 3 30.08.2013 13:47
Исключение символа перед строкой (регулярное выражение) setter Общие вопросы Javascript 11 08.08.2011 09:51
регулярное выражение theo_ Общие вопросы Javascript 15 21.06.2010 10:29