【问题标题】:Why isn't java.util.regex.matcher not matching all instances in this string?为什么 java.util.regex.matcher 不匹配此字符串中的所有实例?
【发布时间】:2016-04-15 20:10:26
【问题描述】:

我有以下代码:http://ideone.com/mFUaqG

import java.util.regex.Matcher;
import java.util.regex.Pattern;

class RegexUtils
{
    private static final Pattern resourceURLCSS     = Pattern.compile("url\\([\'\"](((?!://).)*)[\'\"]\\)");
    private static final Pattern resourceURLHTML    = Pattern.compile("(href|src|url)=[\'\"](((?!://).)*)[\'\"]");

    public static String makeCSSURLsAbsolute(String input, String baseURL)
    {
        Matcher matcher     = resourceURLCSS.matcher(input);
        return matcher.replaceAll("url('"+baseURL+"$1')");
    }
    public static String makeHTMLURLsAbsolute(String input, String baseURL)
    {
        Matcher matcher     = resourceURLHTML.matcher(input);
        return matcher.replaceAll("$1=\""+baseURL+"$2\"");
    }

    public static void main(String[] args)
    {
        String fixed    = RegexUtils.makeCSSURLsAbsolute("div#header { background-image: url('images/header-background.jpg'); } div#header { background-image: url('images/header-background.jpg'); }", "http://www.google.ca/");
        System.out.println(fixed);

        fixed           = RegexUtils.makeHTMLURLsAbsolute("href=\"wtfguys.css\" href=\"wtfguys.css\"", "http://www.google.ca/");
        System.out.println(fixed);
    }
}

不幸的是,这段代码没有达到我的预期,即用字符串替换替换所有出现的正则表达式。我们本质上是用绝对 URLS 替换 CSS 和 HTML 中的相对 URL。它似乎只替换了第一次出现,给了

div#header { background-image: url('http://www.google.ca/images/header-background.jpg'); } div#header { background-image: url('images/header-background.jpg'); }
href="http://www.google.ca/wtfguys.css" href="wtfguys.css"

作为输出。有什么建议吗?

【问题讨论】:

    标签: java regex matcher replaceall


    【解决方案1】:

    您正在使用尝试匹配单引号和双引号属性值的正则表达式。问题是,您可能会匹配一个截断的值,因为这两种模式都不能确保开头的引号与结尾的引号匹配。此外,值本身应该缺少该引号。

    因此,将开始引用包装到捕获组中,使用后向引用作为结束分隔符,并添加后向引用作为回火贪婪令牌中前瞻的替代。然后,修复替换模式,因为反向引用的顺序会改变。

    private static final Pattern resourceURLCSS     = Pattern.compile("url\\((['\"])((?:(?!://|\\1).)*)\\1\\)");
    private static final Pattern resourceURLHTML    = Pattern.compile("(href|src|url)=(['\"])((?:(?!://|\\2).)*)\\2");
    
    public static String makeCSSURLsAbsolute(String input, String baseURL)
    {
        Matcher matcher     = resourceURLCSS.matcher(input);
        return matcher.replaceAll("url('"+baseURL+"$2')");
    }
    public static String makeHTMLURLsAbsolute(String input, String baseURL)
    {
        Matcher matcher     = resourceURLHTML.matcher(input);
        return matcher.replaceAll("$1=\""+baseURL+"$3\"");
    }
    

    IDEONE demo

    【讨论】:

      【解决方案2】:

      .* 很贪心。匹配器将wtfguys.css" href="wtfguys.css 捕获为$2,而不是wtfguys.css。您可以改用.*?[^\"]*,因为URL 内部甚至没有转义引号。此问题的参考解释了几个选项(包括 Wiktor 提到的那个):http://www.rexegg.com/regex-quantifiers.html#greedytrap

      【讨论】:

      • 解决方案可能是通过在* 之后添加? 使其不贪婪。
      • 不,我认为缓和的贪婪令牌应该是固定的,这不仅仅是关于懒惰或贪婪的量词。否则,周围不会有[\'\"]s。需要另一个捕获组、反向引用和负前瞻中的替代项。
      • 不需要支持转义序列,这些不是 C 字符串。
      猜你喜欢
      • 2023-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多