Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.19.30.232] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте!
Парсю XML на Java. К вебу отношение очень слабое, но задаю вопрос здесь, т.к. вопрос именно по регуляркам. Стоит задача построить дерево элементов, со всеми атрибутами. Есть регулярка поиска тегов, открывающих и закрывающих, с атрибутами: [^<]*\<\s*(/?[\w]+)(\s+([\w-]+)\s*=\s*("([^"]*)"|'([^']*)'))*\s*(\s/)?\> Для каждого тега есть подвыражение, которое должно вычленять атрибуты, которых неизвестное кол-во: (\s+([\w-]+)\s*=\s*("([^"]*)"|'([^']*)'))* Упростим его: (\s+[\w-]+=("[^"]*"|'[^']*'))* Суть в том, что извлекается только последняя пара имя_атрибута = заначение, а не все. Когда первый раз такая задача встала, она была решена так (парсился URL): ((name1|name2|name3| ... |nameN)/([^/]+)/)* Заранее известны были имена параметров, поэтому можно было воспользоваться тем, что если в параметрах есть |, то выбираются все разные последние соответствия. Как можно перестроить регулярку, не зная заранее имена атрибутов? Спасибо. |
Сообщ.
#2
,
|
|
|
Цитата (\s+[\w-]+=("[^"]*"|'[^']*'))* Суть в том, что извлекается только последняя пара имя_атрибута = заначение, а не все. А каким образом ты пытаешься получить все эти пары? Как, по-твоему, это должно работать? И что на этот счет говорит документация? |
Сообщ.
#3
,
|
|
|
String sp = "" + "[^<]*" + "<" + "\\s*" + "(/?[\\w]+)" //+ "(" + "(" + "\\s+" + "([\\w-]+)" + "\\s*" + "=" + "\\s*" + "(" + "\"([^\"]*)\"" + "|" + "'([^']*)'" + ")" + ")*" //+ ")" + "\\s*" + "(\\s/)?" + ">" ; //s = "</div>"; Pattern p = Pattern.compile(sp/*, Pattern.MULTILINE */); System.out.println(p.pattern()); // tag name Matcher m = p.matcher(s); while (m.find()) { System.out.println(m.group(1)); // tag name for (int i = 0; i < m.groupCount(); i++) { System.out.println(m.group(i)); } System.out.println("-------------------end\n\n"); } Проверил на одной из страниц этого форума, изменив следующий фрагмент (измененная строка обособлена): s = "<script type='text/javascript' src='http://forum.sources.ru/html/jqcd/jqcd.js'></script>\n" + "<script type='text/javascript' src='http://forum.sources.ru/html/global.js?15'></script>\n" + "\n" + "<table id='b-header' border='0' width='100%' cellspacing='0' cellpadding='1'>\n" + "<tr id='logostrip'>\n" + "<td class='b-logo-wrapper' id = \"test-id\" data-one='one' data-two=\"two\"><a class='e-logo-link' href='http://www.sources.ru' title='На главную'><img class='e-logo-img' src='style_images/1/logo4.gif' alt='На главную' border='0'></a></td>\n" + "\n" + "<td align='center' class='b-slogan-wrapper'>\n" + "<!-- SLOGAN -->\n" + "</td>\n" + "\n"; результат: Цитата td <td class='b-logo-wrapper' id = "test-id" data-one='one' data-two="two"> td data-two="two" data-two "two" two one -------------------end 1) Записано только последнее подвыражение (two) 2) Предпоследнее (one) попало только как значение оказалось в результате потому. что оно стоит в других кавычках, а там идеи ИЛИ для каждых кавычек своим значением, потому что с каждыми кавычками получается одно уникальное подвыражение. В документации java по этому поводи не нашел ничего, но на PHP с тем же столкнулся и тогда нашел где-то, уже не помню где, что это фича. |
Сообщ.
#4
,
|
|
|
Цитата (\s+([\w-]+)\s*=\s*("([^"]*)"|'([^']*)'))* Разъясняю "на пальцах": Это выражение захватывает все параметры сразу (т. к. это самая длинная подходящая подстрока), уже захваченная подстрока в дальнейшем поиске не участвует. Следовательно, m.find() срабатывает только один раз для каждого тега. В найденном наборе для каждой подмаски захватывается только одна подстрока, т. е. из всех пар имя=значение возвращается только одна пара. Почему именно последняя? Потому что так проще реализовать - меньше лишних проверок. В общем, все логично и ожидаемо. Что делать? Очень просто: вырезать найденный тег в отдельную строку, а затем на эту строку натравить ([\w-]+)\s*=\s*("([^"]*)"|'([^']*)'), и тогда последовательный поиск выдаст все нужные пары. P. S. Я с явой не знаком, деталей реализации регвыров на ней не знаю, если в чем-то ошибся - поправьте. |
Сообщ.
#5
,
|
|
|
Это понятно, с этим смирился уже. Вопрос в том, как переделать регулярку, чтобы извлекать тег и его атрибуты сразу, а не в два прохода, потому что так быстрее.
Придумал костыльное решение на ограниченное число параметров: повторение n раз в выражении фрагмента (\s+([\w-]+)\s*=\s*("([^"]*)"|'([^']*)'))? - уже с '?', т.е. 0 или 1 раз, а после этого поставил ((\s+([\w-]+)\s*=\s*("([^"]*)"|'([^']*)'))*) - вычленитель строки с оставшимися атрибутами, чтобы сохранить и потом допарсить. Получил желаемый результат, можно пройтись циклом и смэпить имя=>значение, но это только для максимум n атрибутов. Добавлено результат: Цитата <td class='b-logo-wrapper' id = "test-id" data-one='one' data-two="two"> td class='b-logo-wrapper' class 'b-logo-wrapper' null b-logo-wrapper id = "test-id" id "test-id" test-id null data-one='one' data-one 'one' null one data-two="two" data-two "two" two null null null null null null null null null null null null null null null null -------------------end |
Сообщ.
#6
,
|
|
|
Цитата Вопрос в том, как переделать регулярку, чтобы извлекать тег и его атрибуты сразу, а не в два прохода Как бы переделать паровоз в космический корабль? Никак. Регвыры не всесильны, и, представь себе, есть такие задачи, для решения которых регвыры непригодны. Хотя, чисто теоретически, возможно, в какой-нибудь реализации регвыров есть способ захватывать для подмаски список, а не единственную подстроку. Но это уже извращение. |
Сообщ.
#7
,
|
|
|
Пока вопрос решен повтором подмаски для одного атрибута вручную с квантификатором {0,1}, а что не уместилось в кол-во повтором будет допарсиваться позже отдельно.
|