Я пытаюсь написать правильное регулярное выражение для поиска значения в html, но есть некоторые проблемы.
Есть кусок html:
<div class="inner">
<div class="title">Processing 3-D Secure Transaction</div>
<form autocomplete="off" name="PAResForm" id="PAResForm" action="https://www.alfaportal.ru/" method="POST">
<input name="MD" type="hidden" value="4326381105C3B67B2823E71FD235FFD2"><input value="eJzVWFmvo0iy/iulnkerm9UYt1xdQtJ2pkQdOVw5AW2qGv+is66Q
qrz9LBZ3mCe7mJzYARdloC1dJ/Lk+nQ7KBxxdgtIEgy/Tp/I93MZ5NtZzfdTnPdj5vfz7tex6I/n
4P8DRkGf4Q==" name="PaRes" type="hidden">
Я пытаюсь искать строку
<input name="MD" type="hidden" value="4326381105C3B67B2823E71FD235FFD2">
и получить ценность
Проблема в значении, и имя может заменить друг друга. Например
<input value="4326381105C3B67B2823E71FD235FFD2" type="hidden" name="MD">
Я написал шаблон регулярного выражения:
<input.*name=\"MD\"|value=\"([^<>]*?)\"[^<>]*value=\"([^<>]*?)\"|name=\"MD\".*?>
он работает в некоторых онлайн-сервисах регулярных выражений, но не работает в реальной Java.
Помогите, пожалуйста, изменить его правильно.
Также я написал простой инструмент командной строки для его тестирования. http://pastebin.com/Pzynqrn8
Наконец, я решил это, добавив еще один шаблон. Сначала я ищу строку типа <input... name='MD'.../>
по шаблону ".*?(<input[^<>]*name=\\\"MD\\\"[^<>]*>).*?"
и после этого я ищу значение в строке результата с шаблоном ".*?value=\\\"(.*?)\\\""
Спасибо всем за помощь
<input name='MD' data-js-process-this-value="true" value="4326381105C3B67B2823E71FD235FFD2" type="hidden"/>
... Теперь ваше регулярное выражение может извлечь" true "вместо желаемого значения. Также обратите внимание, что сайт может изменить кавычки с "
двойных кавычек '
одинарные кавычки. Ваше регулярное выражение этого не ожидает.
\s
перед именами атрибутов, и поймайте использованные кавычки, а затем сделайте обратную ссылку на них при закрытии. Создайте ежедневную работу, которая проверяет сайт на соответствие вашему регулярному выражению и уведомляет вас, когда сайт был изменен. Потому что это будет в какой-то момент.
Существует множество инструментов для разбора HTML. Я думаю, вы не должны игнорировать их. Это обсуждалось здесь.
Я не знаю, как это сделать на Java, но я настоятельно рекомендую использовать соответствующие инструменты Document Object Model и т.д.
В PHP я бы сделал это:
$xml = new DomDocument();
$xml->loadXml($yourHTMLHere);
$xpath = new DOMXPath($xml);
$node = $xpath
->evaluate('//form[@name="PAResForm"]//input[@name="MD"]')
->item(0);
$yourValueIsHere = $node->getAttribute('value');
5 строк, полностью читаемых и не заботятся о порядке атрибутов. Java может сделать то же самое точно, просто найдите подходящие классы.
И не анализируйте нерегулярный язык с помощью выражений. Html не является обычным языком.
Я думаю попробовать что-то вроде этого:
<input\s*?(value=['"].*?['"]\s*)|(type=['"].*?["']\s*)|(name=['"].*?['"]\s*)\>
Как всегда, всегда, всегда, когда приходится обращаться с HTML: используйте синтаксический анализатор. Regex не справляется с задачей, по техническим причинам, объясненной смертью в известной должности.
Java имеет jSoup, и смущающе легко создать небольшую, простую и удобную часть кода, которая делает именно то, что вам нужно.
Document doc = Jsoup.parse(str);
Element input = doc.select("input[name='MD']").first();
if (input != null) {
String value = input.attr("value");
// now do something with it
}
Теперь сравните этот трехстрочный слой со всеми этими волосатыми регулярными выражениями, подумайте о том, насколько они доступны и небезопасны, сколько объяснений они требуют и как вы можете полностью переписать их с нуля, когда HTML изменяется. Подсчитайте, когда вы пытались найти решение для себя и решаете, стоит ли регулярное выражение, когда дело касается HTML.
Я бы использовал lookahead в подобном шаблоне:
<input(?=[^>]+?name="MD")[^>]+?value="([A-Z0-9]+)"
Вы в основном говорите, что ищете элемент <input>
с name
MD. Это выглядит: (?=[^>]+?name="MD")
), который не потребляет никаких символов, но гарантирует, что ваш атрибут name
присутствует. Затем вы просто сопоставляете значение value
в первой группе захвата: ([A-Z0-9]+)
.
Возможно, было бы полезно написать шаблон в режиме свободного интервала:
<input # opening input tag
(?=[^>]+?name="MD") # lookahead looking for the presence of the name attribute
[^>]+? # anything (whitespace, other attributes) up to ...
value="([A-Z0-9]+)" # the value attribute and its value
[Обновить] Обратите внимание, что почти всегда лучше использовать правильные синтаксические анализаторы HTML для анализа HTML - что они подходят. В этом случае использование регулярных выражений на мой взгляд прекрасное. Просто имейте в виду следующего парня, который должен будет поддерживать ваш код и принимать ответственное решение.
Пока ваш элемент имеет эти атрибуты, это не сложно:
public static void main(String[] args) {
Pattern p = Pattern.compile("<input(?:\\s+|name=\"MD\"|type=\"hidden\"|value=\"([^\"]+)\")+");
Matcher m = p.matcher("<input name=\"MD\" type=\"hidden\" value=\"4326381105C3B67B2823E71FD235FFD2\">");
if (m.find()) {
System.out.println(m.group(1));
}
}