【问题标题】:regular expression replace two group正则表达式替换两组
【发布时间】:2013-04-03 15:36:54
【问题描述】:

我有这样的模式:<[a-zA-Z][^>]*(?:poster|src)=(['\"])([^'\"]+)\\1[^>]*> 这里我想替换 src 或 poster 属性的值。

没关系

<video src='srcVal' />

<video poster='posterVal' src='srcVal' />

但对于

<video poster='posterVal' src='srcVal' />

仅更改 src 值,因为 matcher.group(2) 仅返回 srcVal

public class Test {
    public static void main(String[] args) throws Exception {
        String html = "<video poster='posterVal' src='srcVal' />";
        Pattern resourcePattern = Pattern.compile("<[a-zA-Z][^>]*(?:poster|src)=(['\"])([^'\"]+)\\1[^>]*>");
        Matcher matcher = resourcePattern.matcher(html);
        int last = 0;
        StringBuilder sb = new StringBuilder();
        while(matcher.find()) {
            String path = matcher.group(2) + "Changed";
            sb.append( html.substring(last, matcher.start(2)) + path );
            last = matcher.end(2);
        }
        sb.append(html.substring(last));
        System.out.println(sb);
        //outputs <video poster='posterVal' src='srcValChanged' />
        //expecting <video poster='posterValChanged' src='srcValChanged' />
    }
}

有没有人知道如何做到这一点?

【问题讨论】:

  • 试试看这里:Java Regex
  • 当您关心语言的结构而不是文本的精确表示时,我不建议您使用正则表达式。也就是说,您正在解析 XML 方言,并且在 XML 中属性的顺序无关紧要 - 但正则表达式不能轻易表示“顺序无关紧要”。使用真正的XML库,有很多选择。
  • 他们不容易,但他们仍然可以。前瞻和条件正则表达式是可用于实现此类目标的 2 个工具。
  • 我接受@drquicksilver 的建议。我将使用 xml 解析器和 xpath 来更改值。因此,单一模式不可能发生这样的事情。就像刚琴老胡推荐的教程一样,多用一种模式就可以实现。

标签: java regex replace


【解决方案1】:

我不会用正则表达式做这个,但你可以试试这样的事情:

<[a-zA-Z]*[^>]*(?:(poster)|src)=(['\"])([^'\"]+)\\2(?(1)[^>]*(?:src=(['\"])([^'\"]+)\\4)?[^>]*|[^>]*(?:poster=(['\"])([^'\"]+)\\6)?[^>]*)>

虽然我现在没有时间测试它,抱歉。

编辑:
不太注重性能:

<[a-zA-Z]*(?=(?:[^>]*?poster=['\"]([^'\"]+))?)(?=(?:[^>]*?src=['\"]([^'\"]+))?)[^>]*(?:poster|src)[^>]*>

如果您只想匹配视频标签,请将其更改为(因为它会大大改进它):

<video(?=(?:[^>]*?poster=['\"]([^'\"]+))?)(?=(?:[^>]*?src=['\"]([^'\"]+))?)[^>]*(?:poster|src)[^>]*>

解释:(我想它一定看起来很令人不安)

我们使用 2 次前瞻来捕捉有趣的内容。 Lookaheads 将允许我们检查两次前面的内容,因此忽略顺序。但是,这些前瞻必须始终有效(使用 * 和 ? 来确保这一点),但仍然是贪婪的,同时又是懒惰的(什么?):我们必须在看到海报/src 时立即停止,但要走得足够远抓住那些。 .*?a? 总是一无所获。所以我们在这里使用(?:.*?a)?。这里的行为是尝试用懒惰的方式捕捉 a,如果它失败了,这不是问题。
正则表达式的最后一部分是确保我们只捕获带有海报或 src 属性的标签,因为我们的前瞻只做那个捕获,当然不能用来做那个。

请注意,我删除了对您的属性的检查,因为无论如何它都没用。

【讨论】:

  • 我想我明白你想怎么做,但它抱怨 (?(1)...) 部分。谢谢。
  • 该死,我以为 Java 支持条件正则表达式。我会多加考虑的。
【解决方案2】:

基本问题在于表达式开头附近的[^&gt;]*。因为* 是贪婪的,所以它会吃掉尽可能多的字符,同时仍然允许表达式的其余部分匹配,所以给定

<video poster='posterVal' src='srcVal' />

[^&gt;]* 将吞噬ideo poster='posterVal' 直到并包括src= 之前的空格。

我会以不同的方式处理它,而不是尝试编写一个匹配整个标签的正则表达式,只需编写一个匹配您感兴趣的属性的正则表达式,然后替换该表达式的 all 匹配项

html.replaceAll("\\b((?:poster|src)=)(['\"])([^'\"]+)\\1", "$1$2$3Changed$2")

但正如其他发帖者所评论的那样,使用能够理解该语言的适当解析器而不是尝试使用正则表达式来操纵文本表示会更明智。

【讨论】:

  • 这不是他的问题。无论顺序如何,他都想抓住两者。
  • 如果我有一个像 src="my.png" 这样的 html,它将改变纯文本,而不仅仅是元素属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-25
  • 2012-08-01
  • 2020-08-02
  • 1970-01-01
  • 1970-01-01
  • 2018-10-20
  • 1970-01-01
相关资源
最近更新 更多