如何判断字符串是否已经进行了URL编码?

70

如何检查字符串是否已经被编码?

例如,如果我对TEST==进行编码,我会得到TEST%3D%3D。 如果我再次对最后一个字符串进行编码,我会得到TEST%253D%253D,在这之前我需要知道它是否已经被编码了...

我保存了已编码的参数,并且需要搜索它们。 我不知道输入参数是编码还是未编码的,因此在搜索之前我需要知道是否必须对它们进行编码或解码。


1
同意。您已经接受了一个错误的答案。 - Paul Kienitz
1
导入 java.net.URIString url = "www.demo.demo/demo file not encoded.jpg" boolean isEncoded = true; try { URI x = new URI(url) } catch(Exception ex) { isEncoded = false; } - Rami Sharaiyri
9个回答

55

解码并与原始内容进行比较。如果不同,则原始内容已被编码。如果没有差异,则原始内容未被编码。但仍然不能确定新解码版本是否仍然被编码。递归的好任务。

希望urlencode无法编写Quine程序,否则此算法将被卡住。

例外情况:当字符串包含“+”字符时,url解码器会将其替换为空格,即使该字符串没有进行url编码。


1
好的,除非“足够好”已经足够;如果0.01%的用户真的希望程序不工作,那么它对他们来说就不会工作。有时候额外的、极端的条款只是得不偿失和增加负担。 - SF.
12
如果您的字符串包含类似于%DESCRIPTION%的Windows变量名,则会失败,该名称解码为ÞSCRIPTION%,或者像%ABOUT%这样的变量名则变成了«OUT% - benrifkah
3
@SF.:如果初始未编码字符串中间包含“+”字符,这种方法将失败。解码后的字符串将包含一个空格字符,它与原始字符串不相等。更好的方法是比较长度。如果原始字符串比解码后的字符串更长,则原始字符串已被编码。 - stan
4
如果原始字符串中包含加号,则无法正常工作。您需要对其进行解码,与原始字符串进行比较,发现两个字符串不同。加号已被替换为空格。最终您将不进行编码,尽管应该这样做。 - ceiroa
5
这是错误的。当一个字符串包含“+”字符时,URL解码器会将其替换为空格,即使该字符串没有进行URL编码。请参阅http://docs.oracle.com/javase/6/docs/api/java/net/URLDecoder.html。 - Prabhath Suminda
显示剩余10条评论

20

使用正则表达式检查您的字符串是否包含非法字符(即在URL编码字符串中找不到的字符,例如空格)。


我没有做这个,但这是解决方案。 - Trick
13
那么,您如何区分hello%20worldinterest20%growth?第一个是有效的URL编码字符串,而另一个字符串必须进行转义,并且不能产生有效的反转义。 - SF.
2
检查非法字符时不包括百分号符号,因为它不是非法的,只是被转义了。当您检查百分号符号时,如果其后跟着“25”,则可能具有URI编码字符串。这仅在您知道输入未经编码或仅编码一次输入不自然地包含URI编码生成的序列时才有效。 - benrifkah
不幸的是,这并不是解决方案。我将一个URL作为加密字符串传递,所以我进行了REFind(':',str)操作,并返回6(https:),无论该字符串是否被加密。 - Chris Geirman
3
如果一个字符串包含无效字符,那么你可以证明它没有被编码,但是如果它只包含有效字符和百分号,那并不能证明它已经被编码。这是无法确定的。因此,这可能是我们能够现实地进行的最好检查。 - Paul Kienitz

5

尝试解码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

如果URL以将空格替换为“+”的方式进行编码,则此方法将无法正常工作,因为长度保持不变。 - Florian K
可能最好只将您的URL编码为%20。优点在这里描述:https://dev59.com/vnE85IYBdhLWcg3wpFKu#2678602如果不可能,那么也许您可以在 ? 后检查 + 号,如果发现任何一个,则该URL已经编码,您可以按原样返回它。这只是对上述代码的额外检查,具体取决于您的用例。 - amit_saxena

2

除非您的字符串符合某种模式,或者您跟踪您的字符串,否则您无法确定。正如您自己指出的那样,编码的字符串也可以被重新编码,因此仅通过查看字符串本身,您不能百分之百确定。


2

请检查您的URL是否存在可疑字符[1]。以下是可能存在问题的字符列表:

空格,", <,>,{,},|,\,^,~,[,],.和`

我使用的是:

private static boolean isAlreadyEncoded(String passedUrl) {
        boolean isEncoded = true;
        if (passedUrl.matches(".*[\\ \"\\<\\>\\{\\}|\\\\^~\\[\\]].*")) {
                isEncoded = false;
        }
        return isEncoded;
}

对于实际编码,我采用以下方法:

https://dev59.com/8Ggv5IYBdhLWcg3wMN0U#49796882

注意:即使您的URL不包含不安全字符,您可能仍希望对主机名应用Punnycode编码等。因此,仍有很多空间进行额外的检查。


[1] 候选列表可以在URL规范第2页的“不安全”部分中找到。在我看来,“%”或“#”应该在编码检查中留出,因为这些字符也可能出现在编码的URL中。


2

使用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();
    }
}

感谢您的回答,确认在使用Spring的Java中按预期工作。 - cppxaxa

-1

根据规范(https://www.rfc-editor.org/rfc/rfc3986),所有的URL 必须 以方案后跟一个 : 开始。

由于冒号是方案和URI其余部分之间的分隔符,任何包含冒号的字符串都不会被编码。

(这假设您不会收到没有方案的不完整URI。)

因此,您可以测试字符串是否包含冒号,如果没有,则对其进行urldecode,如果该字符串包含冒号,则原始字符串已经进行了url编码,如果没有,则检查字符串是否不同,如果是,则再次进行urldecode,如果不是,则它不是有效的URI。

如果您知道可以预期哪些方案,则可以使此循环更简单。


-1

如果您想确保字符串已正确编码(如果需要编码),只需解码并再次进行编码即可。

元代码:

100%_correctly_encoded_string = encode(decode(input_string))

已经编码的字符串将保持不变。未编码的字符串将被编码。只包含URL允许字符的字符串也将保持不变。


2
不行。使用一个包含“%s”的未编码字符串进行测试。异常将导致设计如此的代码无法执行,因为它会引发由无效“%xy”引起的InvalidArgumentException。这与被接受的答案存在相同的问题,并且会引发其他糟糕的设计缺陷,例如忽略未知的异常类型。 - Darrin

-2
由于这个答案的帮助,我编写了一个函数(JS语言),它只使用encodeURI一次对URL进行编码,因此您可以调用它以确保仅对其进行一次编码,而无需知道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"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接