import java.util.BitSet;/*** 判断一个字符串是不是URL编码字符串的工具类,即判断字符串是不是application/x-www-form-urlencoded字符串** @author liaowenxiong* @date 2022/1/14 11:32*/public class URLEncodeUtils {private static BitSet bitSet;static {bitSet = new BitSet(256);int i;// 将小写英文字母添加到BitSet对象中for (i = 'a'; i <= 'z'; i++) {bitSet.set(i);}// 将大写英文字母添加到BitSet对象中for (i = 'A'; i <= 'Z'; i++) {bitSet.set(i);}// 将阿拉伯数字添加到BitSet对象中for (i = '0'; i <= '9'; i++) {bitSet.set(i);}// 将其它URL编码保留的字符或ASCII字符添加到BitSet对象中bitSet.set('+');bitSet.set('-');bitSet.set('_');bitSet.set('.');bitSet.set('*');}/*** 判断字符串是否被URL编码过,即是否URLEncoder.encode过<br>* 经常遇到这样的情况,拿到一个URL,但是搞不清楚到底要不要encode<br>* 不做encode吧,担心出错,做encode吧,又怕重复了<br>* URL编码格式:* 将' '转成'+' <br>* 0-9a-zA-Z保留 <br>* '-','_','.','*'保留 <br>* 其他字符转成%XX的格式,X是16进制的大写字符,范围是[0-9A-F]* <p>* 这里会有误差,比如输入一个字符串 123+456,它到底是原文就是123+456还是123 456做了URL编码后的内容呢?<br>* 又比如123%2B456,它到底是原文,还是123+456URL编码后的内容呢? <br>* 我认为只要符合URL编码规范的,就当作已经URL编码过了<br>** @param str* @return*/public static boolean hasUrlEncoded(String str) {boolean needEncode = false;for (int i = 0; i < str.length(); i++) {char c = str.charAt(i);// 判断字符是不是URL编码保留字符(或者叫作ASCII字符),是就可以不要编码,也就是可以认为已经URL编码过了if (bitSet.get((int) c)) {continue;}// 不是ASCII字符,那么就判断是否符合URL编码的格式:%XX,X是16进制数if (c == '%' && (i + 2) < str.length()) {char c1 = str.charAt(++i);char c2 = str.charAt(++i);// 判断是否为十六进字符if (isDigit16Char(c1) && isDigit16Char(c2)) {continue;}}// 即不是不是ASCII字符,也不符合URL编码格式,表示字符串不是URL编码字符串needEncode = true;break;}return !needEncode;}/*** 判断c是否是16进制的字符** @param c* @return*/private static boolean isDigit16Char(char c) {return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');}
}