【问题标题】:Perfect URL validation regex in JavaJava中完美的URL验证正则表达式
【发布时间】:2015-10-05 02:31:14
【问题描述】:

我找到了该页面:https://mathiasbynens.be/demo/url-regex,其中很好地列出了用于 URL 验证的不同正则表达式及其可能性。 Diego Perini 的正则表达式是最强大的,我想在 Java 中使用它。但是,如果我这样使用它就行不通了:

public class URLValidation {
    // "\" replaced by "\\"
    private static Pattern REGEX = Pattern.compile("_^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!10(?:\\.\\d{1,3}){3})(?!127(?:\\.\\d{1,3}){3})(?!169\\.254(?:\\.\\d{1,3}){2})(?!192\\.168(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\x{00a1}-\\x{ffff}0-9]+-?)*[a-z\\x{00a1}-\\x{ffff}0-9]+)(?:\\.(?:[a-z\\x{00a1}-\\x{ffff}0-9]+-?)*[a-z\\x{00a1}-\\x{ffff}0-9]+)*(?:\\.(?:[a-z\\x{00a1}-\\x{ffff}]{2,})))(?::\\d{2,5})?(?:/[^\\s]*)?$_iuS");

    private static String[] URLs = new String[] { "http://foo.com/blah_blah", "http://foo.com/blah_blah/", "http://foo.com/blah_blah_(wikipedia)", "http://foo.bar?q=Spaces should be encoded" };

    public static void main(String[] args) throws Exception {
        for (String url : URLs) {
            Matcher matcher = REGEX.matcher(url);
            if (matcher.find()) {
                System.out.println(matcher.group());
            }}}}

此代码不输出任何内容,但它应该输出数组中的前三个 URL。如何正确编译正则表达式以使代码正常工作?

upd:感谢您的建议。我在实际应用程序中测试了您的正则表达式。我在那里做的是遍历日志文件并在每一行中查找 URL。日志文件的时间戳和用户名分别包含在 [] 和 中,有时可能包含负责格式化(颜色、粗体等)的特殊不可见字符,例如 \u0003。正则表达式似乎对那种类型的字符串有问题:http://ideone.com/WEcgBY

upd2:如果正则表达式包含多个 URL,那么如何查找一行中的所有 URL?例如像这样使用它:

String[] urlsFromLine = REGEX.split(line);
for (String url : urlsFromLine) {
    System.out.println(url);
}

【问题讨论】:

    标签: java regex url


    【解决方案1】:

    使用这个版本:

    "(?i)^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$"
    

    您不必将斜杠加倍,在模式末尾添加正则表达式分隔符、修饰符,并将 \u 转换为 \x 表示法。

    IDEONE demo:

    String[] URLs = new String[] { "http://foo.com/blah_blah", "http://foo.com/blah_blah/", "http://foo.com/blah_blah_(wikipedia)", "http://foo.bar?q=Spaces should be encoded" };
    Pattern REGEX = Pattern.compile("(?i)^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$");
    for (String url : URLs) {
        Matcher matcher = REGEX.matcher(url);
        if (matcher.find()) {
           System.out.println(matcher.group());
        }
    }
    

    输出:

    http://foo.com/blah_blah
    http://foo.com/blah_blah/
    http://foo.com/blah_blah_(wikipedia)
    

    更新

    要匹配较大文本中的 URL,您需要将 ^$ 替换为 \\b

    Pattern REGEX = Pattern.compile("(?i)\\b(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?\\b");
    

    another demo

    【讨论】:

    • 这意味着您需要调整此正则表达式以匹配较大字符串中的 URL。您需要将^$ 替换为\\b,一个单词边界。
    • 这是用占位符替换真实 URL 的 IDEONE。我会尝试一个单词边界。
    • 我对你有下一个要求:)
    • 不要使用split,在这种情况下它不起作用。
    • 啊。但是我可以使用 "\\s" 拆分一个字符串,然后使用怪物正则表达式评估生成的字符串,对吗?
    猜你喜欢
    • 2011-07-30
    • 1970-01-01
    • 2014-09-15
    • 2021-02-24
    • 1970-01-01
    • 1970-01-01
    • 2015-09-07
    • 2013-08-24
    相关资源
    最近更新 更多