Java - конвертировать строку в действительный объект URI

Я пытаюсь получить java.net.URIобъект от String. В строке есть несколько символов, которые необходимо заменить на их escape-последовательности в процентах. Но когда я использую URLEncoder для кодирования строки с кодировкой UTF-8, даже / заменяются их escape-последовательностями.

Как я могу получить действительный закодированный URL из объекта String?

http://www.google.com?q=a b дает http% 3A% 2F% 2www.google.com ... тогда как я хочу, чтобы вывод был http://www.google.com?q=a% 20b

Может кто-нибудь подскажите пожалуйста как этого добиться.

Я пытаюсь сделать это в приложении для Android. Так что у меня есть доступ к ограниченному количеству библиотек.

21.02.2009 15:07:19
11 ОТВЕТОВ
РЕШЕНИЕ

Вы можете попробовать: org.apache.commons.httpclient.util.URIUtil.encodeQueryв проекте Apache commons-httpclient

Вот так (см. URIUtil ):

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

станет:

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

Конечно, вы можете сделать это самостоятельно, но разбор URI может стать довольно грязным ...

56
15.05.2014 21:27:04
Спасибо, Ганс. Я пытаюсь сделать это в приложении для Android. Так что у меня есть доступ к ограниченному количеству библиотек. Есть ли у вас другие предложения?
lostInTransit 21.02.2009 20:53:05
Возможно, вы могли бы взглянуть на источник класса URIUtil (в конце концов, это открытый исходный код). Я бы предположил, что из этого класса можно извлечь необходимый код.
Hans Doggen 22.02.2009 15:39:36
Указанный проект (Apache commons-httpclient) "теперь конец жизни". Он был частично заменен HttpComponents-httpclient, но мне не удалось найти эквивалентный метод в новом API.
dgiugg 6.08.2014 13:24:54
Я согласен с dgiugg. Ответ не рекомендуется.
Sarp Kaya 7.04.2015 03:04:49
Похоже, что он не существует для новых версий коммитов apache -httpclient
Daniel 18.06.2015 21:42:14

Вы можете использовать много аргументные конструкторы 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
5.12.2013 13:39:34

В блоге java.net на днях был класс, который мог бы делать то, что вы хотите (но сейчас он недоступен, поэтому я не могу проверить).

Этот код, вероятно, может быть изменен, чтобы сделать то, что вы хотите:

http://svn.apache.org/repos/asf/incubator/shindig/trunk/java/common/src/main/java/org/apache/shindig/common/uri/UriBuilder.java

Вот то, о чем я думал из java.net: https://urlencodedquerystring.dev.java.net/

1
21.02.2009 21:50:13

Если вам не нравятся библиотеки, как насчет этого?

Обратите внимание, что вы не должны использовать эту функцию на всем URL, вместо этого вы должны использовать это на компонентах ... например, только компонент "ab", когда вы создаете URL - иначе компьютер не будет знать, какие символы предполагается использовать иметь особое значение, и какие из них должны иметь буквальное значение.

/** 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;
}
9
26.07.2010 07:07:35
Это не работает (по крайней мере, в некоторых случаях). Например, символ «Š» кодируется как «% M1», но должен кодироваться как «% C5% A0».
mindas 10.05.2011 10:47:50
Это также не работает для таких символов, как табуляция. Я бы посоветовал изменить это на небезопасное, если оно не соответствует [A-Za-z0-9 _-. ~]. См. En.wikipedia.org/wiki/Percent-encoding
Gray -- SO stop being evil 19.07.2011 20:06:49

Или, возможно, вы могли бы использовать этот класс:

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

Который присутствует в Android начиная с уровня API 1.

Досадно, однако, что он обрабатывает пробелы специально (заменяя их на + вместо% 20). Чтобы обойти это, мы просто используем этот фрагмент:

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

1
14.11.2013 10:07:00
Это дало бы google.com?q=a+b не google.com?q=a%20b, как хотелось бы.
rpcutts 7.03.2011 14:42:26
Ах, да, нашел себя через несколько недель. Изменим ответ, чтобы отразить то, что мы в действительности используем
MrCranky 8.03.2011 09:39:46
Этот метод теперь устарел, пользователи должны указать метод кодирования, см .: docs.oracle.com/javase/1.4.2/docs/api/java/net/URLEncoder.html
Aidanc 12.11.2013 18:49:42
Правда, я пропустил это. Ответ исправлен.
MrCranky 14.11.2013 10:06:21

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"));
45
7.04.2011 15:21:23
Большое спасибо! Смешно, сколько времени иногда требуется, чтобы найти простую функцию Java!
Abdo 27.09.2012 07:57:16
К сожалению, метод encode () бесполезен при попытке закодировать косую черту ("/"). Я просто использовал простой старый String.replace (), чтобы выполнить работу. Это было очень неубедительно ... searchQuery.replace ("/", "% 2f");
Bogdan Zurac 28.02.2013 17:12:10

У меня были похожие проблемы для одного из моих проектов по созданию объекта 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);
4
21.05.2014 11:50:05
Не обрабатывает преобразование вопросительного знака (я попробовал это с URL: http://www.google.com/Do you like Spam?и он позаботился о
kentcdodds 27.03.2012 18:57:36
@kentcdodds это потому, что в этом случае знак вопроса является законным. Я уверен, что если вы добавите еще один после, он будет преобразован
Sebas 12.01.2016 16:55:39

Я собираюсь добавить одно предложение, предназначенное для пользователей 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-адреса и заставить ее работать, не требуя каких-либо специальных знаний о ней самостоятельно.

34
22.01.2012 17:02:51

Ну, я пытался с помощью

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

Надеюсь, это то, что вы на самом деле искали?

3
12.07.2012 08:22:09
Это ответ, который я искал и не требует зависимости от внешних библиотек.
Michael Plautz 1.08.2014 17:12:14
Нет, это неправильный ответ. URLDecoder.decode("to convert","UTF-8") возвращает «конвертировать» и URLDecoder.decode("to%20convert","UTF-8")возвращает «конвертировать». Так что это противоположно тому, что задает вопрос.
Sarp Kaya 7.04.2015 03:25:38

Даже если это старый пост с уже принятым ответом, я публикую свой альтернативный ответ, потому что он хорошо работает для данной проблемы, и, кажется, никто не упомянул этот метод.

С библиотекой java.net.URI:

URI uri = URI.create(URLString);

И если вы хотите строку в формате URL, соответствующую ей:

String validURLString = uri.toASCIIString();

В отличие от многих других методов (например, java.net.URLEncoder), этот метод заменяет только небезопасные символы ASCII (например ç, é...).


В приведенном выше примере, если URLStringэто следующее String:

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

в результате validURLStringбудет:

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

который является хорошо отформатированным URL.

14
6.08.2014 13:54:54
Ваш ответ был тот, который я искал, я не мог извлечь параметр по разным причинам, и это единственный метод, который действительно работал.
Ramin 14.12.2015 09:14:56
И все должны также взглянуть на документацию при работе с исключениями developer.android.com/reference/java/net/…
Junior M 28.12.2015 20:22:33
Кажется, это не конвертирует кавычки? то есть ''
behelit 1.11.2017 04:38:41
@behelit Правда, только что проверил. Тем не менее, 'это безопасный характер . Но "выдвигает исключение! То же самое с java.net.URL.
dgiugg 2.11.2017 08:39:44

В итоге я использовал 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
0
12.02.2015 04:51:42