场景
用户使用HTML编辑器把自己的文章上传到后台,我需要提取img标签的图片URL地址,用于做图片的鉴黄等内容安全操作。
代码实现
一共用了三个文件,分别是 RegexUtils.java ImgTagUtils.java 和 Main.java
RegexUtils 类封装了正则表达式。ImgTagUtils类负责提取HTML代码中的图片URL地址。Main类包含著主方法,用于测试。
RegexUtils
package blog141;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式工具类
* @author zhangchao
*/
public final class RegexUtils {
/**
* 获得匹配正则表达式的内容
* @param str 字符串
* @param reg 正则表达式
* @param isCaseInsensitive 是否忽略大小写,true忽略大小写,false大小写敏感
* @return 匹配正则表达式的字符串,组成的List
*/
public static List<String> getMatchList(final String str, final String reg, final boolean isCaseInsensitive) {
ArrayList<String> result = new ArrayList<String>();
Pattern pattern = null;
if (isCaseInsensitive) {
//编译正则表达式,忽略大小写
pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
} else {
//编译正则表达式,大小写敏感
pattern = Pattern.compile(reg);
}
Matcher matcher = pattern.matcher(str);// 指定要匹配的字符串
while (matcher.find()) { //此处find()每次被调用后,会偏移到下一个匹配
result.add(matcher.group());//获取当前匹配的值
}
result.trimToSize();
return result;
}
/**
* 获取第一个匹配正则表达式的子串
* @param str 完整字符串
* @param reg 正则表达式
* @param isCaseInsensitive 是否忽略大小写,true表示忽略,false表示大小写敏感。
* @return 第一个匹配正则表达式的子串。
*/
public static String getFirstMatch(final String str, final String reg, final boolean isCaseInsensitive) {
Pattern pattern = null;
if (isCaseInsensitive) {
//编译正则表达式,忽略大小写
pattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);
} else {
//编译正则表达式,大小写敏感
pattern = Pattern.compile(reg);
}
Matcher matcher = pattern.matcher(str);// 指定要匹配的字符串
if (matcher.find()) {
return matcher.group();
}
return null;
}
}
ImgTagUtils
package blog141;
import java.util.ArrayList;
import java.util.List;
/**
* img标签工具类
* @author zhangchao
*/
public final class ImgTagUtils {
/**
* 从html代码中,获得指定标签的指定属性的取值
* @param html HTML代码
* @param tagName 指定的标签名称
* @param propertyName 指定的属性名称
* @return
*/
public static List<String> listTagPropertyValue(final String html, final String tagName, final String propertyName) {
// 结果集合
ArrayList<String> result = new ArrayList<>();
// 找出HTML代码中所有的tagName标签
List<String> list = RegexUtils.getMatchListIgnoreCase(html, "<" + tagName + "[^>]*>");
// 循环遍历每个标签字符串,找出其中的属性字符串,比如 src=....
for (String tagStr : list) {
// 去掉标签结尾的/>,方便后面 src 属性的正则表达式。
// 这样可以适应 <video src=http://www.yourhost.com/xxx/> 这样的标签
if (tagStr.endsWith("/>")) {
tagStr = tagStr.substring(0, tagStr.length() - 2);
tagStr = tagStr + " ";
}
// 去掉标签结尾的>,方便后面匹配属性的正则表达式。
// 这样可以适应 <video src=http://www.yourhost.com/xxx> 这样的标签
else if (tagStr.endsWith(">")) {
tagStr = tagStr.substring(0, tagStr.length() - 1);
tagStr = tagStr + " ";
}
// 去掉字符串开头的 <video 或 <source
tagStr = tagStr.substring(1 + tagName.length());
tagStr = " " + tagStr;
// 取出属性的值
String regSingleQuote = "^" + propertyName + "='[^']*'"; // 使用单引号
String regDoubleQuote = "^" + propertyName + "=\"[^\"]*\""; // 使用双引号
String reg = "^" + propertyName + "=[^\\s]*\\s"; // 不使用引号
int index = 0;
int length = tagStr.length();
while (index <= length) {
String subStr = tagStr.substring(index);
// 单引号
String str = RegexUtils.getFirstMatch(subStr, regSingleQuote, true);
if (null != str) {
// 往后跳过已经匹配的字符串。
index += str.length();
String srcStr = str;
srcStr = srcStr.trim();
// 去掉 src=
srcStr = srcStr.substring(propertyName.length() + 1);
// 去掉单引号
srcStr = srcStr.substring(1);
srcStr = srcStr.substring(0, srcStr.length() - 1);
// 结果中加入图片URL
result.add(srcStr);
}
// 双引号
else if ((str = RegexUtils.getFirstMatch(subStr, regDoubleQuote, true)) != null) {
// 往后跳过已经匹配的字符串。
index += str.length();
String srcStr = str;
srcStr = srcStr.trim();
// 去掉 src=
srcStr = srcStr.substring(propertyName.length() + 1);
// 去掉双引号
srcStr = srcStr.substring(1);
srcStr = srcStr.substring(0, srcStr.length() - 1);
// 结果中加入图片URL
result.add(srcStr);
}
// 不使用引号
else if ((str = RegexUtils.getFirstMatch(subStr, reg, true)) != null) {
// 往后跳过已经匹配的字符串。
index += str.length();
String srcStr = str;
srcStr = srcStr.trim();
// 去掉 src=
srcStr = srcStr.substring(propertyName.length() + 1);
// 结果中加入图片URL
result.add(srcStr);
}
// 其他属性-单引号
else if ((str = RegexUtils.getFirstMatch(subStr, "^[\\w|-]+='[^']*'", true)) != null) {
// 往后跳过已经匹配的字符串。
index += str.length();
}
// 其他属性-双引号
else if ((str = RegexUtils.getFirstMatch(subStr, "^[\\w|-]+=\"[^\"]*\"", true)) != null) {
// 往后跳过已经匹配的字符串。
index += str.length();
}
else {
index ++;
}
}
} // end for (String tagStr : list)
result.trimToSize();
return result;
}
/**
* 从html代码中找出img标签的图片路径
* @param html HTML代码
* @return 字符串列表,里面每个字符串都是图片链接地址
*/
public static List<String> listImgSrc(final String html) {
return listTagPropertyValue(html, "img", "src");
}
}
Main
package blog141;
import java.util.List;
public class Main {
public static void main(String[] args) {
String html = "<p>asdfasdfsdf</p>\n" +
"<img src=https://img.yourhost.com/FqzDkQNPHjd9erjJ5RzRuV8sPqKH>\n" +
"<p>明明嘻嘻嘻</p>\n" +
"<Img src=\"https://img.yourhost.com/ba262e63fa0bb4aace45a645d6\"></img><p>一生一世意义</p>京东方克拉夫的啦" +
"jldksfjal打算离开房间拉萨地方 <img src='https://img.yourhost.com/img01.jpg'/> 打开拉萨附近卢卡斯京东方 <IMG Src=/yourpath/1.png/>\n" +
"<img style=\"width:100px\"src='/aaa/aaa.jpg'></img";
List<String> list = ImgTagUtils.listImgSrc(html);
for (String str : list) {
System.out.println(str);
}
}
}
输出结果:
https://img.yourhost.com/FqzDkQNPHjd9erjJ5RzRuV8sPqKH
https://img.yourhost.com/ba262e63fa0bb4aace45a645d6
https://img.yourhost.com/img01.jpg
/yourpath/1.png
/aaa/aaa.jpg