Java URI 转义器,其工作方式类似于 Java 脚本的 unescape
Java URI escaper which works like the Javascript's unescape
我有一个像 http://google.com/search/q=<%= name %>
这样的字符串。
我无法控制的第三方 js 库正在将其转义为 "http://google.com/search/q=%3C%=%20name%20%%3E"
哪个Java脚本可以使用
成功反转义为原始字符串
unescape("http://google.com/search/q=%3C%=%20name%20%%3E")
但是 Java 的 URLDecode.decode("http://google.com/search/q=%3C%=%20name%20%%3E")
抛出一个 IllegalArgumentException
因为字符串中的未转义文字 %
字符当然是正确的并且符合规范,但是这使得服务器端处理变得复杂。
在我尝试用正则表达式修复服务器端糟糕的JS转义之前(因为如前所述,我无法修改JS端),我想知道是否有更宽松的Java URL/URI 解码 API 其工作方式与 Java 脚本的 unescape
相同,即忽略独立的 '%' 字符,只解码可解码的内容。
我快速浏览了一些 Apache 库并遇到了同样的问题。有趣的是,当我跟进 EMCAScript 语言规范时,我发现了 unescape() 函数的伪代码。你可以在 https://tc39.github.io/ecma262/#sec-unescape-string
看到这个
将它的简单实现放在一起(见下文)很容易,至少对于您问题中的示例,输出匹配。
现在这段代码没有经过任何优化,我也没有考虑过字符编码是否相关,但与尝试使用 Regex 解决问题相比,这可能是一种更轻松的前进方式。
public static String unescape(String s) {
StringBuilder r = new StringBuilder();
for (int i = 0; i < s.length();) {
if (s.charAt(i) == '%') {
if (looksLikeUnicode(s, i)) {
r.append((char) fromHex(s, i + 2, i + 5));
i += 6;
continue;
}
if (looksLikeAscii(s, i)) {
r.append((char) fromHex(s, i + 1, i + 2));
i += 3;
continue;
}
}
r.append(s.charAt(i));
i += 1;
}
return r.toString();
}
private static boolean looksLikeUnicode(String s, int i) {
return (i + 5 < s.length()) && (s.charAt(i + 1) == 'u') && areHexDigits(s, i + 2, i + 5);
}
private static boolean looksLikeAscii(String s, int i) {
return (i + 2 < s.length()) && areHexDigits(s, i + 1, i + 2);
}
private static boolean areHexDigits(String s, int from, int to) {
for (int i = from; i <= to; ++i) {
if (isNotHexDigit(s.charAt(i))) {
return false;
}
}
return true;
}
private static boolean isHexDigit(char c) {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
private static boolean isNotHexDigit(char c) {
return !isHexDigit(c);
}
private static int fromHex(String s, int from, int to) {
return Integer.parseInt(s.substring(from, to + 1), 16);
}
我有一个像 http://google.com/search/q=<%= name %>
这样的字符串。
我无法控制的第三方 js 库正在将其转义为 "http://google.com/search/q=%3C%=%20name%20%%3E"
哪个Java脚本可以使用
成功反转义为原始字符串unescape("http://google.com/search/q=%3C%=%20name%20%%3E")
但是 Java 的 URLDecode.decode("http://google.com/search/q=%3C%=%20name%20%%3E")
抛出一个 IllegalArgumentException
因为字符串中的未转义文字 %
字符当然是正确的并且符合规范,但是这使得服务器端处理变得复杂。
在我尝试用正则表达式修复服务器端糟糕的JS转义之前(因为如前所述,我无法修改JS端),我想知道是否有更宽松的Java URL/URI 解码 API 其工作方式与 Java 脚本的 unescape
相同,即忽略独立的 '%' 字符,只解码可解码的内容。
我快速浏览了一些 Apache 库并遇到了同样的问题。有趣的是,当我跟进 EMCAScript 语言规范时,我发现了 unescape() 函数的伪代码。你可以在 https://tc39.github.io/ecma262/#sec-unescape-string
看到这个将它的简单实现放在一起(见下文)很容易,至少对于您问题中的示例,输出匹配。
现在这段代码没有经过任何优化,我也没有考虑过字符编码是否相关,但与尝试使用 Regex 解决问题相比,这可能是一种更轻松的前进方式。
public static String unescape(String s) {
StringBuilder r = new StringBuilder();
for (int i = 0; i < s.length();) {
if (s.charAt(i) == '%') {
if (looksLikeUnicode(s, i)) {
r.append((char) fromHex(s, i + 2, i + 5));
i += 6;
continue;
}
if (looksLikeAscii(s, i)) {
r.append((char) fromHex(s, i + 1, i + 2));
i += 3;
continue;
}
}
r.append(s.charAt(i));
i += 1;
}
return r.toString();
}
private static boolean looksLikeUnicode(String s, int i) {
return (i + 5 < s.length()) && (s.charAt(i + 1) == 'u') && areHexDigits(s, i + 2, i + 5);
}
private static boolean looksLikeAscii(String s, int i) {
return (i + 2 < s.length()) && areHexDigits(s, i + 1, i + 2);
}
private static boolean areHexDigits(String s, int from, int to) {
for (int i = from; i <= to; ++i) {
if (isNotHexDigit(s.charAt(i))) {
return false;
}
}
return true;
}
private static boolean isHexDigit(char c) {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
private static boolean isNotHexDigit(char c) {
return !isHexDigit(c);
}
private static int fromHex(String s, int from, int to) {
return Integer.parseInt(s.substring(from, to + 1), 16);
}