【问题标题】:Customize HTML img tags with Java Regular Expressions使用 Java 正则表达式自定义 HTML img 标签
【发布时间】:2013-09-24 22:07:14
【问题描述】:

我是正则表达式的新手,但我相信这是我解决方案的方法。我正在尝试采用任意 HTML sn-p 并自定义图像标签。例如,

如果我有这个 HTML 代码: <><><><><img src="blah.jpg"><><><><><><><><img src="blah2.jpg"><><><>

我想把它变成: <><><><><img src="images/blah.jpg"><><><><><><><><img src="images/blah2.jpg"><><><>

我现在的代码是这样的:

Pattern p = Pattern.compile("<img.*src=\".*\\..*\"");
Matcher m = p.matcher(htmlString);
boolean b = m.find();

String imgPath = "src=\"images/";

while(b)
{
    //Get file name.
    String name="test.jpg\"";

    //Assign new path.
    m.group().replaceAll("src=\".*\"",imgPath+name);
}

【问题讨论】:

  • 我不知道我在做什么。我不知道正则表达式应该是什么样子,也不知道如何用修改后的版本替换原始 HTML。
  • 问题是你不应该使用正则表达式来解析 HTML。例如,.* 仅搜索同一行中的字符,因此 imgsrc 之间的返回会中断搜索。其次,img.*src 是不正确的:这会搜索 img 和任意数量的字符以及 last 在同一行上出现的src。你不想要那个;它会在您的示例中以相同的结果捕获两个图像。 HTML 属性可以有单引号而不是双引号。 HTML 允许 = 符号周围的空格,但您的正则表达式不允许。以此类推。
  • 我明白你在说什么,但同时我不知道如何继续使用另一种方法来分解 HTML 标签。然而,我现在有某种功能代码,但有一些问题。 img 标签正在定制,但我现在遇到的问题是它总是将每个 img 标签设置为相同的定制。例如, 对于所有的 img 标签都会变成 。
  • 我无法从您在此处发布的 Java 源代码中看到您到底想要做什么。 (这是一个无限循环,因为b 永远不会改变。)我很确定基本问题就像我提到的那样:正则表达式返回&lt;img src="blah"&gt;&lt;&gt;&lt;&gt;&lt;&gt;&lt;img src="blah2" 而不仅仅是&lt;img src="blah"
  • 由于我已经接近解决方案,我会考虑使用 switch 语句来解决您提到的一些变体(或者我可以尝试更多地了解正则表达式,以可能想出更好的东西)。用最简单的术语来说,我试图获取源属性并在文件名之前插入一个文件夹名。此外,如果我可以得到 img 标签上的所有匹配项,那么我可以根据需要得到所有文件名,我的代码就差不多完成了。

标签: java html regex


【解决方案1】:

Regular expressions are not the correct way to parse HTML.别这样。不可能做到正确。

Use a proper parser.

Document doc = Jsoup.parse(someHtml);
Elements imgs = doc.select("img");
for (Element img : imgs) {
    img.attr("src", "images/" + img.attr("src")); // or whatever
}

doc.outerHtml(); // returns the modified HTML

【讨论】:

    【解决方案2】:

    这段代码几乎是完美的。它会打印出很多信息,因此请查找显示“最终结果”和“原始”的位置以查看自定义 IMG 标签的结果。有一个小缺陷,我仍然不知道如何修复。 “in10”是用于测试输入字符串的变量。其余的都是正则表达式。

    我注意到,当我使用换行符以及将“src=”留空而不是“src=\”\“”或“src=''”时,会出现问题。引号似乎会影响结果。

    private static String r16 = "(?s)(<img.*?)(src\\s*?=\\s*?(?:\"|').*?(?:\"|'))";
    private static String in10 = "<><><><><img width=1 height=888 src=\"bnm.jpg\"<><><><><img src=\"\"> <img src = \"\"><img src ='folder1/folder2/bnm.jpg'><><><img src =\"'>";
    private static String r14 = "(?s)\\/|\\=";
    
    
    
    
        String path="images/";
        String name="";
    
       Pattern p = Pattern.compile(r16);
    
       Matcher m = p.matcher(in10); 
    
    
       StringBuffer sb = new StringBuffer();
       int i=1;
       while(m.find())
       {
            String g0 = m.group();
            String g2 = m.group(2);
            System.out.println("Main group"+i+":"+g0);
            System.out.println("Inner group1:"+m.group(1));
            System.out.println("Inner group2:"+g2);
    
    
    
    
                String[] names=g2.split(r14);
                printNames(names);
    
                /*
                 * src="/folder1/folder2/blah.jpg"  --->  blah.jpg
                 * src="bnm.jpg"                    --->  src="bnm.jp"
                 */
    
                if(names.length>=1)
                {
                    name = names[names.length-1];
                }
                else
                {
                    name = "";
                }
            //Name might be empty string.
            name = name.replaceAll("\"|'","");
            System.out.println("Retrieved Name:"+name);
            m.appendReplacement(sb,"$1src=\""+path+name+"\"");
            i++;
       }
       m.appendTail(sb);
        INPUT=sb.toString();
       System.out.println("Final Result:"+INPUT);
       System.out.println("Original____:"+in10);
       System.out.println("Count:"+m.groupCount());        
    }
    

    【讨论】:

    • 我对上面的正则表达式做了一些小的调整。我现在相信代码可以工作,但需要执行更多测试。特别是,r17 包括 "(?s)" 和 r14 = "(?s)\\/|(\\s*+\\=\\s*+)" 还要注意,但一个非常小的细节是何时src='' 被替换了,不管用什么引号,我总是用双引号替换,而不是让前面的引号原封不动。
    • 更新:r17 完全删除,不再需要。一些测试显示 r16 的正则表达式需要更改,因为它不应该与 src= 或 src=\" 或 src=' 匹配,换句话说,必须使用某种双引号。另外,我不知道如何在 Windows O/S 中表示换行符,因此对于我使用的测试字符串: System.getProperty("line.separator") 在字符串中表示换行符;使用换行符时代码似乎按预期工作。
    • 我意识到 r16 只有 src='src=' 有问题,换句话说,如果 src= 是嵌套的。我不知道如何从匹配中否定并删除它。以前我显示错误的原始字符串并认为我的模式与 src= 匹配,但实际上并非如此。我会更新代码。
    【解决方案3】:

    你不应该为此使用正则表达式。josh3736 所说的方式是健壮的。但是如果你想使用正则表达式,你应该使用:

    String s = "<><><><><img src=\"blah.jpg\"><><><><><><><><img src=\"blah2.jpg\"><><><>";
    s = s.replaceAll("(?<=img src=\")([^\"]+)(?=\">)","images/$1");
    System.out.println(s);
    

    输出:

    <><><><><img src="images/blah.jpg"><><><><><><><><img src="images/blah2.jpg"><><><>
    

    【讨论】:

      【解决方案4】:

      虽然我同意其他人的观点,即使用正则表达式执行此操作是修改 html 片段的错误方法,但这里有一个 JUnit 测试用例,展示了如何用 Java 中的模式替换 src 元素:

      import static org.junit.Assert.*;
      import static org.hamcrest.CoreMatchers.*;
      
      import java.util.regex.Pattern;
      import java.util.regex.Matcher;
      
      import org.junit.Test;
      
      public class ImgSrcReplace {
      
        @Test
        public void replaceWithRegex() {
          String dir = "image/";
          String htmlFragment = "<body>\n"+
          "<img src=\"single-line.jpg\">"+
          "<img src=\n"+
          "\"multiline.jpg\">\n"+
          "<img src='single-quote.jpg'><img src=\"broken.gif\'>"+
          "<img class=\"before\" src=\"class-before.jpg\">"+
          "<img src=\"class-after.gif\" class=\"after\">"+
          "</body>";
      
      
          Pattern replaceImgSrc =
            Pattern.compile(
              "(<img\\b[^>]*\\bsrc\\s*=\\s*)([\"\'])((?:(?!\\2)[^>])*)\\2(\\s*[^>]*>)",
              Pattern.CASE_INSENSITIVE&Pattern.MULTILINE);
      
          String result = 
            replaceImgSrc.matcher(htmlFragment)
              .replaceAll("$1$2"+Matcher.quoteReplacement(dir)+"$3$2$4");
      
          assertThat("the single line image tag was updated", result, 
            containsString("image/single-line.jpg"));
          assertThat("the multiline image tag was updated", result, 
            containsString("image/multiline.jpg"));
          assertThat("the single quote image tag was updated", result, 
            containsString("image/single-quote.jpg"));
          assertThat("the broken gif was ignored.", result, 
            containsString("\"broken.gif'"));
          assertThat("attributes before are preseved.", result, 
            containsString("<img class=\"before\" src=\"image/class-before.jpg\">"));
          assertThat("attributes after are preseved.", result, 
            containsString("<img src=\"image/class-after.gif\" class=\"after\">"));
        }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2011-11-20
        • 1970-01-01
        • 1970-01-01
        • 2013-05-21
        • 1970-01-01
        • 2019-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多