Java - String in gültiges URI-Objekt konvertieren

73

Ich versuche ein java.net.URIObjekt von einem zu bekommen String. Die Zeichenfolge enthält einige Zeichen, die durch ihre prozentualen Escape-Sequenzen ersetzt werden müssen. Aber wenn ich URLEncoder verwende, um den String mit UTF-8-Codierung zu codieren, werden sogar die / durch ihre Escape-Sequenzen ersetzt.

Wie kann ich eine gültige codierte URL von einem String-Objekt erhalten?

http://www.google.com?q=a b gibt http% 3A% 2F% 2www.google.com ... während ich möchte, dass die Ausgabe http://www.google.com?q=a% ist 20b

Kann mir bitte jemand sagen, wie ich das erreichen kann?

Ich versuche dies in einer Android-App zu tun. Ich habe also Zugriff auf eine begrenzte Anzahl von Bibliotheken.

lostInTransit
quelle

Antworten:

57

Sie könnten versuchen: org.apache.commons.httpclient.util.URIUtil.encodeQueryim Apache commons-httpclient- Projekt

So (siehe URIUtil ):

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

wird werden:

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

Sie können es natürlich selbst tun, aber das URI-Parsing kann ziemlich chaotisch werden ...

Hans Doggen
quelle
Danke Hans. Ich versuche dies in einer Android-App zu tun. Ich habe also Zugriff auf eine begrenzte Anzahl von Bibliotheken. Haben Sie weitere Vorschläge?
Nochmals vielen
2
Vielleicht können Sie sich die Quelle der URIUtil-Klasse ansehen (sie ist schließlich Open Source). Ich würde annehmen, dass es möglich ist, den erforderlichen Code aus dieser Klasse zu extrahieren.
Hans Doggen
6
Das spitze Projekt (Apache commons-httpclient) "ist jetzt das Ende des Lebens". Es wurde teilweise durch HttpComponents-httpclient ersetzt, aber ich konnte keine entsprechende Methode in der neuen API finden.
dgiugg
2
Ich stimme dgiugg zu. Die Antwort ist veraltet.
Sarp Kaya
1
Es scheint, dass es für neue Versionen der Apache-Commits -httpclient
Daniel
45

Android hatte schon immer die Uri-Klasse als Teil des SDK: http://developer.android.com/reference/android/net/Uri.html

Sie können einfach so etwas tun wie:

String requestURL = String.format("http://www.example.com/?a=%s&b=%s", Uri.encode("foo bar"), Uri.encode("100% fubar'd"));
Bensnider
quelle
4
Danke vielmals! Es ist lächerlich, wie lange es manchmal dauert, eine einfache Java-Funktion zu finden!
Abdo
1
Leider ist die Methode encode () Mist, wenn versucht wird, Schrägstriche ("/") zu codieren. Ich habe gerade einen einfachen alten String.replace () verwendet, um die Arbeit zu erledigen. Das war sehr lahm ... searchQuery.replace ("/", "% 2f");
Bogdan Zurac
34

Ich werde hier einen Vorschlag hinzufügen, der sich an Android-Benutzer richtet. Sie können dies tun, ohne externe Bibliotheken abrufen zu müssen. Außerdem sind alle in einigen der obigen Antworten vorgeschlagenen Lösungen zum Suchen / Ersetzen von Zeichen gefährlich und sollten vermieden werden.

Probieren Sie es aus:

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();

Sie können sehen, dass in dieser bestimmten URL diese Leerzeichen codiert sein müssen, damit ich sie für eine Anfrage verwenden kann.

Dies nutzt einige Funktionen, die Ihnen in Android-Klassen zur Verfügung stehen. Erstens kann die URL-Klasse eine URL in ihre richtigen Komponenten aufteilen, sodass Sie keine Arbeit zum Suchen / Ersetzen von Zeichenfolgen ausführen müssen. Zweitens nutzt dieser Ansatz die URI-Klassenfunktion, um Komponenten ordnungsgemäß zu maskieren, wenn Sie einen URI über Komponenten anstatt aus einer einzelnen Zeichenfolge erstellen.

Das Schöne an diesem Ansatz ist, dass Sie jede gültige URL-Zeichenfolge verwenden können, ohne dass Sie selbst spezielle Kenntnisse darüber benötigen.

Craig B.
quelle
14

Auch wenn dies ein alter Beitrag mit einer bereits akzeptierten Antwort ist, poste ich meine alternative Antwort, da sie für die vorliegende Ausgabe gut funktioniert und anscheinend niemand diese Methode erwähnt hat.

Mit der Bibliothek java.net.URI:

URI uri = URI.create(URLString);

Und wenn Sie eine entsprechende URL-formatierte Zeichenfolge möchten:

String validURLString = uri.toASCIIString();

Im Gegensatz zu vielen anderen Methoden (zB java.net.URLEncoder) dieses eine ersetzt nur unsichere ASCII - Zeichen (wie ç, é...).


Im obigen Beispiel ist if URLStringdas Folgende String:

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

das Ergebnis validURLStringwird sein:

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

Das ist eine gut formatierte URL.

dgiugg
quelle
1
Ihre Antwort war die, nach der ich gesucht habe. Ich konnte den Parameter aus verschiedenen Gründen nicht extrahieren und dies ist die einzige Methode, die wirklich funktioniert hat.
Ramin
Und jeder sollte sich auch die Dokumentation ansehen, wenn es um Ausnahmen geht. Developer.android.com/reference/java/net/…
Junior Mayhé
Dies scheint keine Anführungszeichen umzuwandeln? dh '"
siehe
1
@behelit Stimmt das, nur überprüft. Ist 'jedoch ein sicherer Charakter . Aber "wirft eine Ausnahme auf! Gleiches gilt für java.net.URL.
dgiugg
9

Wenn Sie keine Bibliotheken mögen, wie wäre es damit?

Beachten Sie, dass Sie diese Funktion nicht für die gesamte URL verwenden sollten, sondern für die Komponenten ... z. B. nur für die Komponente "ab", während Sie die URL aufbauen. Andernfalls weiß der Computer nicht, welche Zeichen angenommen werden eine besondere Bedeutung haben und welche eine wörtliche Bedeutung haben sollen.

/** 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;
}
Tim Cooper
quelle
Dies funktioniert nicht (zumindest in einigen Fällen). Das Zeichen 'Š' ist beispielsweise als '% M1' codiert, sollte jedoch als '% C5% A0' codiert werden.
Mindas
Dies funktioniert auch nicht für Zeichen wie Tabulatoren. Ich würde vorschlagen, dass dies geändert wird, um unsicher zu sein, wenn es nicht mit [A-Za-z0-9 _-. ~] Übereinstimmt. Siehe en.wikipedia.org/wiki/Percent-encoding
Gray
4

Sie können die Konstruktoren mit mehreren Argumenten der URIKlasse verwenden. Aus dem URIJavadoc:

Die Konstruktoren mit mehreren Argumenten zitieren unzulässige Zeichen, wie dies für die Komponenten erforderlich ist, in denen sie vorkommen. Das Prozentzeichen ('%') wird von diesen Konstruktoren immer in Anführungszeichen gesetzt. Alle anderen Zeichen bleiben erhalten.

Also, wenn Sie verwenden

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

Dann bekommen Sie, http:www.google.com?q=a%20bwas nicht ganz richtig ist, aber es ist ein bisschen näher.

Wenn Sie wissen, dass Ihre Zeichenfolge keine URL-Fragmente enthält (z. B. http://example.com/page#anchor ), können Sie den folgenden Code verwenden, um das zu erhalten, was Sie möchten:

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

Um sicher zu gehen, sollten Sie die Zeichenfolge nach #Zeichen durchsuchen , aber dies sollte Ihnen den Einstieg erleichtern.

Jason Day
quelle
4

Ich hatte ähnliche Probleme bei einem meiner Projekte, ein URI-Objekt aus einer Zeichenfolge zu erstellen. Ich konnte auch keine saubere Lösung finden. Folgendes habe ich mir ausgedacht:

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;
}

Sie können stattdessen den folgenden URI-Konstruktor verwenden, um bei Bedarf einen Port anzugeben:

URI uri = new URI(scheme, userInfo, host, port, path, query, fragment);
Hervé Donner
quelle
Kann ein Fragezeichen nicht konvertieren (ich habe es mit der URL versucht: http://www.google.com/Do you like Spam?und es hat sich um die Leerzeichen gekümmert, aber nicht um das Fragezeichen am Ende)
kentcdodds
@kentcdodds, weil das Fragezeichen in diesem Fall legal ist. Ich bin sicher, wenn Sie eine weitere hinzufügen, wird sie konvertiert
Sebas
3

Nun, ich habe es versucht

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

Ich hoffe, das ist es, wonach Sie tatsächlich gesucht haben?

Amol Ghotankar
quelle
Dies ist die Antwort, nach der ich gesucht habe und die keine Abhängigkeit von externen Bibliotheken erfordert.
Michael Plautz
1
Nein, das ist eine falsche Antwort. URLDecoder.decode("to convert","UTF-8") Gibt "konvertieren" und URLDecoder.decode("to%20convert","UTF-8")"konvertieren" zurück. Das ist also das Gegenteil von dem, was die Frage stellt.
Sarp Kaya
1

Oder vielleicht könnten Sie diese Klasse verwenden:

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

Welches ist in Android seit API Level 1 vorhanden.

Ärgerlicherweise werden Leerzeichen jedoch speziell behandelt (durch + anstelle von% 20 ersetzt). Um dies zu umgehen, verwenden wir einfach dieses Fragment:

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

MrCranky
quelle
1
Dies würde google.com?q=a+b geben, nicht google.com?q=a%20b wie gewünscht.
schneidet
Ah, ja, fand mich ein paar Wochen später. Wird die Antwort ändern, um zu reflektieren, was wir tatsächlich verwenden
MrCranky
1
Diese Methode ist jetzt veraltet. Benutzer sollten eine Methode zum Codieren angeben, siehe: docs.oracle.com/javase/1.4.2/docs/api/java/net/URLEncoder.html
Aidanc
Das habe ich allerdings verpasst. Antwort geändert.
MrCranky
0

Am Ende habe ich den httpclient-4.3.6 verwendet:

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

Ausgabe wird sein:

http://www.example.com/somepage.php?username=Hello+G%C3%BCnter&p1=paramter+1
Frustriert aufgenommen
quelle