簡體   English   中英

從字符串中檢測並提取 url?

[英]Detect and extract url from a string?

這是一個簡單的問題,但我就是不明白。 我想檢測字符串中的 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;

有什么更好的主意嗎?

讓我繼續並在此之前說我不是復雜情況下正則表達式的大力倡導者。 試圖為這樣的事情寫出完美的表達是非常困難的。 也就是說,我碰巧有一個用於檢測 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/

m.group(1) 為您提供第一個匹配組,即第一個捕獲括號。 這是(https?|ftp|file)

您應該嘗試查看 m.group(0) 中是否存在某些內容,或者用括號將所有模式括起來並再次使用 m.group(1)。

您需要重復您的 find 函數以匹配下一個並使用新的組數組。

檢測 URL 並非易事。 如果它足以讓您獲得以 https?|ftp|file 開頭的字符串,那么它可能沒問題。 你的問題是,你有一個捕獲組, ()和那些只在第一部分 http ...

我會使用 (?:) 將這部分設為非捕獲組,並在整個內容周圍加上括號。

"\\b((?:https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])"

在整個事物周圍加上一些額外的括號(開頭的單詞邊界除外)它應該匹配整個域名:

"\\b((https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])"

我不認為正則表達式匹配整個網址。

https://github.com/linkedin/URL-Detector

        <groupId>io.github.url-detector/</groupId>
        <artifactId>url-detector</artifactId>
        <version>0.1.23</version>

我在這里嘗試了所有示例來提取這些不同的 url,但都不是完美的:

http://example.com
https://example.com.ua
www.example.ua
https://stackoverflow.com/question/5713558/detect-and-extract-url-from-a-string
https://www.google.com/search?q=how+to+extract+link+from+text+java+example&rlz=1C1GCEU_en-GBUA932UA932&oq=how+to+extract+link+from+text+java+example&aqs=鉻..69i57j33i22i29i30.15020j0j7&sourceid=chrome&ie=UTF-8

我寫了我的 regEx 和一種制作它的方法,它可以處理帶有多個鏈接的文本:

private static final String LINK_REGEX = "((http:\\/\\/|https:\\/\\/)?(www.)?(([a-zA-Z0-9-]){2,2083}\\.){1,4}([a-zA-Z]){2,6}(\\/(([a-zA-Z-_\\/\\.0-9#:?=&;,]){0,2083})?){0,2083}?[^ \\n]*)";
private static final String TEXT_WITH_LINKS_EXAMPLE = "link1:http://example.com link2: https://example.com.ua link3 www.example.ua\n" +
        "link4- https://stackoverflow.com/questions/5713558/detect-and-extract-url-from-a-string\n" +
        "link5 https://www.google.com/search?q=how+to+extract+link+from+text+java+example&rlz=1C1GCEU_en-GBUA932UA932&oq=how+to+extract+link+from+text+java+example&aqs=chrome..69i57j33i22i29i30.15020j0j7&sourceid=chrome&ie=UTF-8";

以及返回帶有鏈接的 ArrayList 的方法:

 private ArrayList<String> getAllLinksFromTheText(String text) {
    ArrayList<String> links = new ArrayList<>();
    Pattern p = Pattern.compile(LINK_REGEX, Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(text);
    while (m.find()) {
        links.add(m.group());
    }
    return links;
}

就這樣。 使用 TEXT_WITH_LINKS_EXAMPLE 參數調用此方法,將收到來自文本的五個鏈接。

這個小代碼片段/函數將有效地從 Java 中的字符串中提取 URL 字符串。 我在這里找到了基本的正則表達式,並在 java 函數中使用了它。

我用“|www[.]”部分對基本正則表達式進行了擴展,以捕獲不以“http://”開頭的鏈接

夠了(它很便宜),這是代碼:

//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+&amp;@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&amp;@#/%=~_()|]";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(text);
while(m.find()) {
String urlStr = m.group();
if (urlStr.startsWith("(") &amp;&amp; urlStr.endsWith(")"))
{
urlStr = urlStr.substring(1, urlStr.length() - 1);
}
links.add(urlStr);
}
return links;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM