使用 URI 來校驗 url,如下代碼:
import org.apache.commons.validator.routines.UrlValidator;
import java.net.URI;
import java.net.URISyntaxException;
public class UrlUtils {
public static void main(String[] args) {
String url = "http://www.jiaobuchong.com?name=tom&request={\"hobby\":\"film\"}";
System.out.println(new UrlValidator().isValid(url));
isValidUrl(url);
}
public static boolean isValidUrl(String url) {
try {
URI uri = new URI(url);
return true;
} catch (URISyntaxException e) {
e.printStackTrace();
}
return false;
}
}
如果 url 含有 {}""
則會拋出 URISyntaxException,校驗不通過。 看了一下 URI 裏面的源碼,有個校驗還挺有意思的。
一、分析 checkChar 方法
1、通過 highMask 獲取合法字符範圍的二進制
private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
private static final long L_LOWALPHA = 0L;
private static final long L_UPALPHA = 0L;
private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
private static final long H_LOWALPHA = highMask('a', 'z');
private static final long H_UPALPHA = highMask('A', 'Z');
checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
L_ALPHA 與的結果是 0,下面就要開始比較有意思的部分了,來看 highMask 到底做了什麼:
// Compute a high-order mask for the characters
// between first and last, inclusive
private static long highMask(char first, char last) {
long m = 0;
// Math.min 表示從 ASCII 的範圍裏取值
// Math.max(Math.min(first, 127), 64) 表示在 ASCII 碼錶[64, 127]之間的字符
// 減去 64 表示不包括 64 這個字符,相對 64 之間還有多少個個字符
int f = Math.max(Math.min(first, 127), 64) - 64;
int l = Math.max(Math.min(last, 127), 64) - 64;
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
highMask(‘a’, ‘z’ ) m 的二進制:
highMask(‘A’, ‘Z’ ) m 的二進制:
H_ALPHA = H_LOWALPHA | H_UPALPHA 相與的結果是:
11111111111111111111111111000000111111111111111111111111110
,相與之後的結果 H_UPALPHA 表示 a-zA-Z
這個範圍的字符,一個蘿蔔一個坑,不在這個範圍的數據對應的坑位就是 0。
2、match 方法
// Tell whether the given character is permitted by the given mask pair
private static boolean match(char c, long lowMask, long highMask) {
if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
return false;
if (c < 64)
return ((1L << c) & lowMask) != 0;
if (c < 128)
// 左移 (c - 64) 位,和 highMask 進行 & 運算,如果不等於 0 就表示這個字符是合法的
return ((1L << (c - 64)) & highMask) != 0;
return false;
}
二、分析 checkChars 方法
通過上面的分析,URI 判斷是否合法字符的原理就是:將和合法範圍的字符轉成一個二進制數,然後將傳進來的字符和這個二進制進行與運算,如果不等於 0 就表示這個字符是合法的。
再來分析一下這個方法:
checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
通過代碼中的計算,L_SCHEME 的結果是:
0 | lowMask('0', '9') | lowMask("+-.")
H_SCHEME:
H_SCHEME = highMask('a', 'z') | highMask('A', 'Z') | 0 | highMask("+-.")
來看 lowMask的代碼,生成的結果 m 表示 [0-9] 二進制的範圍:
// Compute a low-order mask for the characters
// between first and last, inclusive
private static long lowMask(char first, char last) {
long m = 0;
int f = Math.max(Math.min(first, 63), 0);
int l = Math.max(Math.min(last, 63), 0);
for (int i = f; i <= l; i++)
m |= 1L << i;
return m;
}
然後 在 match 方法裏:
// Tell whether the given character is permitted by the given mask pair
private static boolean match(char c, long lowMask, long highMask) {
if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
return false;
if (c < 64)
// 對於小於 64 的字符,和 lowMask 進行與運算,不等於0表示合法的字符
return ((1L << c) & lowMask) != 0;
if (c < 128)
return ((1L << (c - 64)) & highMask) != 0;
return false;
}