如何检查字符串是否已经编码?
例如,如果我编码TEST==
,我得到TEST%3D%3D
. 如果我再次编码最后一个字符串,我会得到TEST%253D%253D
,如果它已经被编码,我必须在这样做之前知道......
我已经保存了编码参数,我需要搜索它们。我不知道输入参数,它们将被编码或不编码,所以我必须知道在搜索之前是否必须对它们进行编码或解码。
如何检查字符串是否已经编码?
例如,如果我编码TEST==
,我得到TEST%3D%3D
. 如果我再次编码最后一个字符串,我会得到TEST%253D%253D
,如果它已经被编码,我必须在这样做之前知道......
我已经保存了编码参数,我需要搜索它们。我不知道输入参数,它们将被编码或不编码,所以我必须知道在搜索之前是否必须对它们进行编码或解码。
解码,对比原版。如果确实不同,则对原始内容进行编码。如果没有差异,则原始文件未编码。但它仍然没有说明新解码的版本是否仍未编码。递归的好任务。
我希望不能用 urlencode 编写 quine,否则这个算法会卡住。
例外:当字符串包含“+”字符时,即使字符串未经过 url 编码,url 解码器也会将其替换为空格
使用正则表达式检查您的字符串是否包含非法字符(即在 URL 编码字符串中找不到的字符,如空格)。
尝试解码网址。如果生成的字符串比原始字符串短,则原始 URL 已经被编码,否则您可以安全地对其进行编码(或者未编码,或者甚至发布编码后 url 保持原样,因此再次编码不会导致错误的 url )。下面是示例伪(受 ruby 启发)代码:
# Returns encoded URL for any given URL after determining whether it is already encoded or not
def escape(url)
unescaped_url = URI.unescape(url)
if (unescaped_url.length < url.length)
return url
else
return URI.escape(url)
end
end
你不能确定,除非你的字符串符合某种模式,或者你跟踪你的字符串。正如您自己指出的那样,编码的字符串也可以编码,因此您不能通过查看字符串本身来 100% 确定。
软件方面的乔尔在某个时候有一个解决方案 - http://www.joelonsoftware.com/articles/Wrong.html
或者您可以在字符串中添加一些前缀。
检查您的 URL 是否有可疑字符[1]。候选人名单:
WHITE_SPACE ,", < , > , { , } , | , \ , ^ , ~ , [ , ] , .
和`
我用:
private static boolean isAlreadyEncoded(String passedUrl) {
boolean isEncoded = true;
if (passedUrl.matches(".*[\\ \"\\<\\>\\{\\}|\\\\^~\\[\\]].*")) {
isEncoded = false;
}
return isEncoded;
}
对于实际的编码,我继续:
https://stackoverflow.com/a/49796882/1485527
注意:即使您的 URL 不包含您可能想要应用的不安全字符,例如对主机名进行 Punnycode 编码。所以还有很大的空间进行额外的检查。
[1] 可以在第 2 页的URL 规范的“不安全”部分中找到候选列表。在我的理解中,编码检查中应该省略“%”或“#”,因为这些字符可以在编码中出现网址也是如此。
使用 Spring UriComponentsBuilder:
import java.net.URI;
import org.springframework.web.util.UriComponentsBuilder;
private URI getProperlyEncodedUri(String uriString) {
try {
return URI.create(uriString);
} catch (IllegalArgumentException e) {
return UriComponentsBuilder.fromUriString(uriString).build().toUri();
}
}
为了避免编码两次并产生错误(正如 OP 所说),我们取消引用而不是再次引用,在 Python 中这将是:
import urllib.parse
urllib.parse.unquote(str)
urllib.parse.quote(str)
如果您想确保字符串编码正确(如果需要编码) - 只需再次对其进行解码和编码。
元代码:
100%_correctly_encoded_string = encode(decode(input_string))
已经编码的字符串将保持不变。未编码的字符串将被编码。仅包含 url 允许字符的字符串也将保持不变。
根据规范(https://www.rfc-editor.org/rfc/rfc3986),所有 URL必须以一个方案开头,后跟一个:
由于需要冒号作为方案和 URI 其余部分之间的分隔符,因此任何包含冒号的字符串都不会被编码。
(这假设您不会得到一个没有方案的不完整 URI。)
所以你可以测试字符串是否包含冒号,如果没有,则对其进行urldecode,如果该字符串包含冒号,则原始字符串是url编码的,如果没有,检查字符串是否不同,如果是,则再次urldecode,如果不是,它不是有效的 URI。
如果你知道你可以期待什么样的方案,你可以使这个循环更简单。
感谢这个答案,我编写了一个函数(JS 语言),它只对 URL 进行一次编码,encodeURI
因此您可以调用它以确保只编码一次,并且您不需要知道 URL 是否已经编码。
ES6:
var getUrlEncoded = sURL => {
if (decodeURI(sURL) === sURL) return encodeURI(sURL)
return getUrlEncoded(decodeURI(sURL))
}
ES6 之前:
var getUrlEncoded = function(sURL) {
if (decodeURI(sURL) === sURL) return encodeURI(sURL)
return getUrlEncoded(decodeURI(sURL))
}
以下是一些测试,因此您可以看到 URL 仅编码一次:
getUrlEncoded("https://example.com/media/Screenshot27 UI Home.jpg")
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(encodeURI("https://example.com/media/Screenshot27 UI Home.jpg"))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(encodeURI(encodeURI("https://example.com/media/Screenshot27 UI Home.jpg")))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(decodeURI("https://example.com/media/Screenshot27 UI Home.jpg"))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"
getUrlEncoded(decodeURI(decodeURI("https://example.com/media/Screenshot27 UI Home.jpg")))
//"https://example.com/media/Screenshot27%20UI%20Home.jpg"