Java-将字符串转换为有效的URI对象


73

我试图从一个java.net.URI对象String。该字符串包含一些字符,需要用其百分比转义序列替换。但是,当我使用URLEncoder以UTF-8编码对String进行编码时,即使将/替换为其转义序列。

如何从String对象获取有效的编码URL?

http://www.google.com?q=a b给出http%3A%2F%2www.google.com ...,而我希望输出为http://www.google.com?q=a% 20b

有人可以告诉我如何实现这一目标。

我正在尝试在Android应用程序中执行此操作。因此,我可以访问数量有限的库。

Answers:


57

您可以尝试:org.apache.commons.httpclient.util.URIUtil.encodeQueryApache commons-httpclient项目中

这样(请参阅URIUtil):

URIUtil.encodeQuery("http://www.google.com?q=a b")

会变成:

http://www.google.com?q=a%20b

您当然可以自己做,但是URI解析会变得非常混乱。


谢谢汉斯。我正在尝试在Android应用程序中执行此操作。因此,我可以访问数量有限的库。你有什么其他的建议?再次感谢
lostInTransit'Feb21

2
也许您可以看一下URIUtil类的源代码(毕竟它是开源的)。我认为可以从该类中提取必要的代码。
汉斯·多根

6
明确的项目(Apache commons-httpclient)“已经寿终正寝”。它已部分替换为HttpComponents-httpclient,但是我无法在新API中找到等效的方法。
dgiugg 2014年

2
我同意dgiugg。答案已过时。
Sarp Kaya 2015年

1
现在看来似乎不适合的阿帕奇提交-httpclient新版本的存在
丹尼尔

45

Android一直将Uri类作为SDK的一部分:http : //developer.android.com/reference/android/net/Uri.html

您可以简单地执行以下操作:

String requestURL = String.format("http://www.example.com/?a=%s&b=%s", Uri.encode("foo bar"), Uri.encode("100% fubar'd"));

4
非常感谢!有时找到一个简单的Java函数要花多长时间真是荒谬!
Abdo 2012年

1
不幸的是,当尝试对正斜杠(“ /”)进行编码时,encode()方法很糟糕。我只是用一个普通的旧String.replace()来完成工作。真是la脚... searchQuery.replace(“ /”,“%2f”);
Bogdan Zurac

34

我将在这里针对Android用户添加一个建议。您可以这样做,避免了必须获取任何外部库的情况。同样,以上某些答案中建议的所有搜索/替换字符解决方案都是危险的,应避免使用。

试试看:

String urlStr = "http://abc.dev.domain.com/0007AC/ads/800x480 15sec h.264.mp4";
URL url = new URL(urlStr);
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
url = uri.toURL();

您可以看到,在此特定的URL中,我需要对那些空格进行编码,以便可以将其用于请求。

这利用了Android类中提供的几个功能。首先,URL类可以将URL分解为适当的组成部分,因此您无需进行任何字符串搜索/替换工作。其次,当您通过组件而不是从单个字符串构造URI时,此方法利用了URI类功能,可以正确地转义组件。

这种方法的优点在于,您可以接受任何有效的url字符串并使它工作,而无需您自己对此有任何特殊的了解。


14

即使这是一个已经接受了答案的旧帖子,我也会发布我的替代答案,因为它在当前问题上效果很好,而且似乎没有人提到此方法。

使用java.net.URI库:

URI uri = URI.create(URLString);

而且,如果您想要与之相对应的URL格式的字符串:

String validURLString = uri.toASCIIString();

与许多其他方法(例如java.net.URLEncoder)不同,此方法仅替换不安全的ASCII字符(如çé...)。


在上面的示例中,ifURLString是以下内容String

"http://www.domain.com/façon+word"

结果validURLString将是:

"http://www.domain.com/fa%C3%A7on+word"

这是格式正确的网址。


1
您的答案是我一直在寻找的答案,由于各种原因我无法提取参数,这是唯一有效的方法。
拉明2015年

每个人都应该有例外打交道时,看看文档developer.android.com/reference/java/net/...
少年Mayhé

这似乎不转换引号?即“”
相信

1
@behelit是的,刚刚检查过。但是,这'是一个安全的字符。但是"引发一个例外!与java.net.URL相同。
dgiugg '17

9

如果您不喜欢图书馆,该怎么办?

请注意,您不应在整个URL上使用此功能,而应在组件上使用此功能...例如,在构建URL时仅使用“ ab”组件-否则计算机将不知道应该使用什么字符具有特殊含义,哪些应该具有字面含义。

/** Converts a string into something you can safely insert into a URL. */
public static String encodeURIcomponent(String s)
{
    StringBuilder o = new StringBuilder();
    for (char ch : s.toCharArray()) {
        if (isUnsafe(ch)) {
            o.append('%');
            o.append(toHex(ch / 16));
            o.append(toHex(ch % 16));
        }
        else o.append(ch);
    }
    return o.toString();
}

private static char toHex(int ch)
{
    return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
}

private static boolean isUnsafe(char ch)
{
    if (ch > 128 || ch < 0)
        return true;
    return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
}

这是行不通的(至少在某些情况下)。例如,字符“Š”被编码为“%M1”,但应被编码为“%C5%A0”。
mindas 2011年

这对于Tab等字符也不起作用。我建议将其更改为不匹配[A-Za-z0-9 _-。〜]时不安全。参见en.wikipedia.org/wiki/Percent-encoding
灰色

4

您可以使用URI该类的多参数构造函数。从URIjavadoc:

多参数构造函数根据出现它们的组件的需要引用非法字符。这些构造函数始终引用百分号('%')。任何其他字符都将保留。

所以如果你用

URI uri = new URI("http", "www.google.com?q=a b");

然后您会得到http:www.google.com?q=a%20b不太正确的信息,但是距离更近了。

如果您知道您的字符串将没有URL片段(例如http://example.com/page#anchor),则可以使用以下代码来获取所需的内容:

String s = "http://www.google.com?q=a b";
String[] parts = s.split(":",2);
URI uri = new URI(parts[0], parts[1], null);

为了安全起见,您应该在字符串中扫描#字符,但这应该可以帮助您入门。


4

我的一个项目从字符串创建URI对象时遇到类似的问题。我也找不到任何干净的解决方案。这是我想出的:

public static URI encodeURL(String url) throws MalformedURLException, URISyntaxException  
{
    URI uriFormatted = null; 

    URL urlLink = new URL(url);
    uriFormatted = new URI("http", urlLink.getHost(), urlLink.getPath(), urlLink.getQuery(), urlLink.getRef());

    return uriFormatted;
}

如果需要,可以使用以下URI构造函数来指定端口:

URI uri = new URI(scheme, userInfo, host, port, path, query, fragment);

不处理转换问号(我尝试使用URL:http://www.google.com/Do you like Spam?并尝试了空格,但没有结尾的问号)
kentcdodds 2012年

@kentcdodds是因为在这种情况下问号是合法的。我确定如果您再添加一个,它将被转换
Sebas 16'Jan

3

好吧,我尝试使用

String converted = URLDecoder.decode("toconvert","UTF-8");

我希望这是您真正想要的?


这是我一直在寻找的答案,不需要依赖外部库。
Michael Plautz

1
不,这是错误的答案。URLDecoder.decode("to convert","UTF-8") 返回“要转换”并URLDecoder.decode("to%20convert","UTF-8")返回“要转换”。因此,这与问题的提出恰恰相反。
Sarp Kaya 2015年


1

或者,您可以使用此类:

http://developer.android.com/reference/java/net/URLEncoder.html

自API级别1起就存在于Android中。

但是,令人讨厌的是,它特别对待空格(用+代替%20代替空格)。为了解决这个问题,我们只需使用以下片段:

URLEncoder.encode(value, "UTF-8").replace("+", "%20");



嗯,是的,几周后发现自己。将修改答案以反映我们最终使用的内容
MrCranky 2011年

1
此方法现已弃用,用户应指定编码方法,请参见: 过时 docs.oracle.com/javase/1.4.2/docs/api/java/net/URLEncoder.html
Aidanc 2013年

是的,我很想念。答案已修正。
MrCranky 2013年

0

我最终使用了httpclient-4.3.6:

import org.apache.http.client.utils.URIBuilder;
public static void main (String [] args) {
    URIBuilder uri = new URIBuilder();
    uri.setScheme("http")
    .setHost("www.example.com")
    .setPath("/somepage.php")
    .setParameter("username", "Hello Günter")
    .setParameter("p1", "parameter 1");
    System.out.println(uri.toString());
}

输出将是:

http://www.example.com/somepage.php?username=Hello+G%C3%BCnter&p1=paramter+1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.