【问题标题】:Detect and extract url from a string?从字符串中检测并提取 url?
【发布时间】:2011-08-08 11:39:14
【问题描述】:

这是一个简单的问题,但我就是不明白。 我想检测字符串中的 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;

有没有更好的办法?

【问题讨论】:

    标签: java regex url


    【解决方案1】:

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

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

    【讨论】:

    • linkedIn url-detector 代码对我不起作用。它从一堆俄语单词中提取了一个 url,其中一个句子的结尾有一个句号,紧接着是下一个句子的开头,点后面没有空格。这是它找到的内容 - дней.Не - 然后在前面添加了 http://,文本中没有。至少它应该排除非拉丁字符吧?
    【解决方案2】:

    我在这里尝试了所有示例来提取不同的网址,但它们都不适合所有人:

    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=chrome..69i57j33i22i29i30.15020j0j7&sourceid=chrome&ie=UTF-8

    我写了我的正则表达式和一个方法,它可以处理带有多个链接的文本:

    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 参数调用此方法,将收到来自文本的五个链接。

    【讨论】:

      【解决方案3】:
      【解决方案4】:

      这个小代码 sn-p / 函数将有效地从 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;
      }
      

      【讨论】:

        【解决方案5】:
        /**
         * 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/
        

        【讨论】:

        • 否决,因为应该有八个反斜杠而不是四个。将它们放在双引号中可以将字符串中的反斜杠数量减少到四个。 \\ 的正则表达式解释以匹配单个 \ 将数字减少到两个,这是您要匹配的。你也可以使用无捕获组,所以(?://|\\\\)
        • 我也犯了同样的错误,我提醒(?://|\\\\\\\\)
        • 关于什么的更新?
        • 非常感谢。对于像我这样的正则表达式新手来说,你的答案是救命稻草。
        【解决方案6】:

        让我继续说,我不是复杂情况下正则表达式的大力倡导者。试图为这样的事情写出完美的表达方式是非常困难的。 也就是说,我碰巧有一个用于检测 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
        }
        

        【讨论】:

        • 不幸的是,这个也匹配了 URL 后面的一个点。
        • 不能正确处理文本中的 URL。前面的空格处理不正确(吞下换行符),并在 URL 后接受冒号、点等。
        • 不适用于&lt;a href="www.google.com"&gt;google link&lt;/a&gt; 之类的东西,它返回"www.google.com
        • 如果 url 在括号中 (www.myurl.com) 不起作用 - 返回“www.myurl.com)”
        • 字符串包含\n时不起作用:Sources:\nhttps://sites.google.com/view/kgssourcesbeauty/startseite\n不被识别为链接
        【解决方案7】:

        检测 URL 并非易事。如果它足以让您获得以 https?|ftp|file 开头的字符串,那么它可能没问题。您的问题是,您有一个捕获组,(),而这些仅在第一部分 http...

        我会使用 (?:) 将此部分设为非捕获组,并在整个内容周围加上括号。

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

        【讨论】:

          【解决方案8】:

          在整个内容周围加上一些额外的括号(开头的单词边界除外),它应该与整个域名匹配:

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

          我不认为正则表达式匹配整个网址。

          【讨论】:

          • 这甚至适用于尾随逗号和空格.. 很棒
          【解决方案9】:

          m.group(1) 为您提供第一个匹配组,即第一个捕获括号。这里是(https?|ftp|file)

          您应该尝试查看 m.group(0) 中是否有某些内容,或者将所有模式用括号括起来并再次使用 m.group(1)。

          您需要重复查找函数以匹配下一个并使用新的组数组。

          【讨论】:

            猜你喜欢
            • 2011-05-22
            • 2020-09-22
            • 2011-08-30
            • 1970-01-01
            • 2012-06-07
            • 1970-01-01
            • 2016-09-18
            相关资源
            最近更新 更多