これは簡単な質問ですが、わかりません。文字列内のURLを検出し、短縮URLに置き換えたい。
Stackoverflowからこの式を見つけましたが、結果はただhttp
です
Pattern p = Pattern.compile("\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]",Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(str);
boolean result = m.find();
while (result) {
for (int i = 1; i <= m.groupCount(); i++) {
String url=m.group(i);
str = str.replace(url, shorten(url));
}
result = m.find();
}
return html;
より良いアイデアはありますか?
m.group(1)は、最初に一致するグループ、つまり最初のキャプチャ括弧を提供します。ここに(https?|ftp|file)
M.group(0)に何かがあるかどうかを確認するか、すべてのパターンを括弧で囲んでm.group(1)を再度使用してください。
次の関数と一致するように検索関数を繰り返し、新しいグループ配列を使用する必要があります。
私が複雑なケースの正規表現の大擁護者ではないと言って、先に進んでこれを始めさせてください。このようなものの完璧な表現を書くことは非常に困難です。 それは言った、たまたまURLを検出するためのものがあり、それは合格する350行のユニットテストケースクラスによってサポートされています。誰かが単純な正規表現から始め、長年にわたり、発見した問題を処理するために式とテストケースを成長させてきました。決して些細なことではありません。
// Pattern for recognizing a URL, based off RFC 3986
private static final Pattern urlPattern = Pattern.compile(
"(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)"
+ "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*"
+ "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
以下に使用例を示します。
Matcher matcher = urlPattern.matcher("foo bar http://example.com baz");
while (matcher.find()) {
int matchStart = matcher.start(1);
int matchEnd = matcher.end();
// now you have the offsets of a URL match
}
/**
* Returns a list with all links contained in the input
*/
public static List<String> extractUrls(String text)
{
List<String> containedUrls = new ArrayList<String>();
String urlRegex = "((https?|ftp|Gopher|telnet|file):((//)|(\\\\))+[\\w\\d:#@%/;$()~_?\\+-=\\\\\\.&]*)";
Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
Matcher urlMatcher = pattern.matcher(text);
while (urlMatcher.find())
{
containedUrls.add(text.substring(urlMatcher.start(0),
urlMatcher.end(0)));
}
return containedUrls;
}
例:
List<String> extractedUrls = extractUrls("Welcome to https://stackoverflow.com/ and here is another link http://www.google.com/ \n which is a great search engine");
for (String url : extractedUrls)
{
System.out.println(url);
}
プリント:
https://stackoverflow.com/
http://www.google.com/
URLの検出は簡単な作業ではありません。 https?| ftp | fileで始まる文字列を取得するのに十分であれば、それで問題ありません。ここでの問題は、キャプチャグループ、()
そして、それらは最初の部分のhttp ...
この部分を(?:)を使用して非キャプチャグループにし、全体を括弧で囲みます。
"\\b((?:https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])"
全体を囲むいくつかの余分な括弧(開始時のWord境界を除く)を使用して、ドメイン名全体と一致する必要があります。
"\\b((https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])"
しかし、正規表現はURL全体と一致するとは思わない。
この小さなコードスニペット/関数は、Javaの文字列からURL文字列を効果的に抽出します。ここでそれを行うための基本的な正規表現を見つけ、Java関数で使用しました。
「http://」で始まらないリンクをキャッチするために、「| www [。]」の部分で基本正規表現を少し拡張しました
十分な話(安い)のコードを次に示します。
//Pull all links from the body for easy retrieval
private ArrayList pullLinks(String text) {
ArrayList links = new ArrayList();
String regex = "\\(?\\b(http://|www[.])[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(text);
while(m.find()) {
String urlStr = m.group();
if (urlStr.startsWith("(") && urlStr.endsWith(")"))
{
urlStr = urlStr.substring(1, urlStr.length() - 1);
}
links.add(urlStr);
}
return links;
}