ジャバ:HTML の大きな文字列があり、href=“…” テキストを抽出する必要があります。
-
13-09-2019 - |
質問
この文字列には HTML の大きな部分が含まれており、文字列の href="..." 部分からリンクを抽出しようとしています。href は次のいずれかの形式になります。
<a href="..." />
<a class="..." href="..." />
正規表現には特に問題はありませんが、次のコードを使用すると、何らかの理由で次のような問題が発生します。
String innerHTML = getHTML();
Pattern p = Pattern.compile("href=\"(.*)\"", Pattern.DOTALL);
Matcher m = p.matcher(innerHTML);
if (m.find()) {
// Get all groups for this match
for (int i=0; i<=m.groupCount(); i++) {
String groupStr = m.group(i);
System.out.println(groupStr);
}
}
誰か私のコードの何が問題なのか教えてもらえますか?私はこれをphpで実行しましたが、Javaではどういうわけか間違ったことをしています...何が起こっているのかというと、印刷しようとするたびにHTML文字列全体が印刷されるということです...
編集:私が扱っている文字列の種類を誰もが知ることができるようにするためです。
<a class="Wrap" href="item.php?id=43241"><input type="button">
<span class="chevron"></span>
</a>
<div class="menu"></div>
コードを実行するたびに、文字列全体が出力されます...それが問題です...
そして、jTidyの使用について...私はそれに取り組んでいますが、この場合も何が問題だったのかを知ることは興味深いでしょう...
解決
.*
これは、引用符を含む任意の文字を取る貪欲な操作です。
のようなものを試してみてください。
"href=\"([^\"]*)\""
他のヒント
あなたが投稿したコードには二つの問題があります。
まず、あなたの正規表現で.*
は貪欲です。これは見つけることができる最後の"
文字までのすべての文字にマッチするようになります。あなたは.*?
にこれを変更することで、この試合は貪欲でないこと作ることができます。
第二に、すべての試合をピックアップし、あなたはMatcher.find
で反復するのではなくグループを探して維持する必要があります。グループでは、正規表現の各括弧で囲まれた部分にアクセスできます。ただし、正規表現全体がマッチするたびに探しています。
は、これらが一緒にあなたが必要なものを行う必要があり、次のコードを与える置きます
Pattern p = Pattern.compile("href=\"(.*?)\"", Pattern.DOTALL);
Matcher m = p.matcher(innerHTML);
while (m.find())
{
System.out.println(m.group(1));
}
正規表現は素晴らしいが、この特定の目的のためではない右のツールです。通常は、このためにstackbasedパーサーを使用します。 jTidy のようなJava HTMLパーサーAPIのを見てます。
組み込みのパーサーを使用します。何かのようなもの:
EditorKit kit = new HTMLEditorKit();
HTMLDocument doc = (HTMLDocument)kit.createDefaultDocument();
doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
kit.read(reader, doc, 0);
HTMLDocument.Iterator it = doc.getIterator(HTML.Tag.A);
while (it.isValid())
{
SimpleAttributeSet s = (SimpleAttributeSet)it.getAttributes();
String href = (String)s.getAttribute(HTML.Attribute.HREF);
System.out.println( href );
it.next();
}
または、ParserCallback を使用します。
import java.io.*;
import java.net.*;
import javax.swing.text.*;
import javax.swing.text.html.parser.*;
import javax.swing.text.html.*;
public class ParserCallbackText extends HTMLEditorKit.ParserCallback
{
public void handleStartTag(HTML.Tag tag, MutableAttributeSet a, int pos)
{
if (tag.equals(HTML.Tag.A))
{
String href = (String)a.getAttribute(HTML.Attribute.HREF);
System.out.println(href);
}
}
public static void main(String[] args)
throws Exception
{
Reader reader = getReader(args[0]);
ParserCallbackText parser = new ParserCallbackText();
new ParserDelegator().parse(reader, parser, true);
}
static Reader getReader(String uri)
throws IOException
{
// Retrieve from Internet.
if (uri.startsWith("http:"))
{
URLConnection conn = new URL(uri).openConnection();
return new InputStreamReader(conn.getInputStream());
}
// Retrieve from file.
else
{
return new FileReader(uri);
}
}
}
Reader は StringReader である可能性があります。
それを行うための別の簡単かつ信頼性の高い方法は、使用している Jsoupする
Document doc = Jsoup.connect("http://example.com/").get();
Elements links = doc.select("a[href]");
for (Element link : links){
System.out.println(link.attr("abs:href"));
}
HTML パーサー ライブラリを使用することもできます。 きちんとした たとえば、HTML の DOM モデルが得られます。そこからすべての「a」要素を抽出し、その「href」属性を読み取ることができます。
"href=\"(.*?)\""
も動作するはずですが、私はクーゲルの答えは高速に動作すると思います。