372 Stimmen

Parsen einer URI-Zeichenkette in eine Name-Werte-Sammlung

Ich habe die URI so eingestellt:

https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback

Ich brauche eine Sammlung mit geparsten Elementen:

NAME               VALUE
------------------------
client_id          SS
response_type      code
scope              N_FULL
access_type        offline
redirect_uri       http://localhost/Callback

Um genau zu sein, brauche ich ein Java-Äquivalent für die C#/.NET HttpUtility.ParseQueryString Methode.

0voto

Jasper de Vries Punkte 16523

En Eclipse Jersey REST-Framework unterstützt dies durch UriComponent . Beispiel:

import org.glassfish.jersey.uri.UriComponent;

String uri = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
MultivaluedMap<String, String> params = UriComponent.decodeQuery(URI.create(uri), true);
for (String key : params.keySet()) {
  System.out.println(key + ": " + params.getFirst(key));
}

0voto

Basit Punkte 8218

Wenn Sie nur die Parameter nach der URL von einem String wollen. Dann wird der folgende Code funktionieren. Ich nehme nur die einfache Url an. Ich meine keine harte und schnelle Überprüfung und Dekodierung. Wie in einem meiner Testfälle habe ich die Url erhalten und weiß, dass ich nur den Wert der Parameter benötige. Die Url war einfach. Keine Kodierung oder Dekodierung erforderlich.

String location = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
String location1 = "https://stackoverflow.com?param1=value1&param2=value2&param3=value3";
String location2 = "https://stackoverflow.com?param1=value1&param2=&param3=value3&param3";

    Map<String, String> paramsMap = Stream.of(location)
        .filter(l -> l.indexOf("?") != -1)
        .map(l -> l.substring(l.indexOf("?") + 1, l.length()))
        .flatMap(q -> Pattern.compile("&").splitAsStream(q))
        .map(s -> s.split("="))
        .filter(a -> a.length == 2)
        .collect(Collectors.toMap(
            a -> a[0], 
            a -> a[1],
            (existing, replacement) -> existing + ", " + replacement,
            LinkedHashMap::new
        ));

    System.out.println(paramsMap);

Danke

0voto

Mike Dudley Punkte 67

Hier ist meine Lösung mit reduzieren. y Optional :

private Optional<SimpleImmutableEntry<String, String>> splitKeyValue(String text) {
    String[] v = text.split("=");
    if (v.length == 1 || v.length == 2) {
        String key = URLDecoder.decode(v[0], StandardCharsets.UTF_8);
        String value = v.length == 2 ? URLDecoder.decode(v[1], StandardCharsets.UTF_8) : null;
        return Optional.of(new SimpleImmutableEntry<String, String>(key, value));
    } else
        return Optional.empty();
}

private HashMap<String, String> parseQuery(URI uri) {
    HashMap<String, String> params = Arrays.stream(uri.getQuery()
            .split("&"))
            .map(this::splitKeyValue)
            .filter(Optional::isPresent)
            .map(Optional::get)
            .reduce(
                // initial value
                new HashMap<String, String>(), 
                // accumulator
                (map, kv) -> {
                     map.put(kv.getKey(), kv.getValue()); 
                     return map;
                }, 
                // combiner
                (a, b) -> {
                     a.putAll(b); 
                     return a;
                });
    return params;
}
  • Ich ignoriere doppelte Parameter (ich nehme den letzten).
  • Ich benutze Optional<SimpleImmutableEntry<String, String>> um später Müll zu ignorieren
  • Die Reduktion beginnt mit einer leeren Karte und füllt sie dann bei jedem SimpleImmutableEntry

Falls Sie fragen, reduzieren. erfordert diesen seltsamen Kombinierer im letzten Parameter, der nur in parallelen Streams verwendet wird. Sein Ziel ist die Zusammenführung zweier Zwischenergebnisse (hier HashMap).

0voto

jungledev Punkte 3859

Ich antworte hier, weil dies ein beliebtes Thema ist. Dies ist eine saubere Lösung in Kotlin, die die empfohlene UrlQuerySanitizer api. Siehe die offizielle Dokumentation . Ich habe einen String Builder hinzugefügt, um die Parameter zu verketten und anzuzeigen.

    var myURL: String? = null

    if (intent.hasExtra("my_value")) {
        myURL = intent.extras.getString("my_value")
    } else {
        myURL = intent.dataString
    }

    val sanitizer = UrlQuerySanitizer(myURL)
    // We don't want to manually define every expected query *key*, so we set this to true
    sanitizer.allowUnregisteredParamaters = true
    val parameterNamesToValues: List<UrlQuerySanitizer.ParameterValuePair> = sanitizer.parameterList
    val parameterIterator: Iterator<UrlQuerySanitizer.ParameterValuePair> = parameterNamesToValues.iterator()

    // Helper simply so we can display all values on screen
    val stringBuilder = StringBuilder()

    while (parameterIterator.hasNext()) {
        val parameterValuePair: UrlQuerySanitizer.ParameterValuePair = parameterIterator.next()
        val parameterName: String = parameterValuePair.mParameter
        val parameterValue: String = parameterValuePair.mValue

        // Append string to display all key value pairs
        stringBuilder.append("Key: $parameterName\nValue: $parameterValue\n\n")
    }

    // Set a textView's text to display the string
    val paramListString = stringBuilder.toString()
    val textView: TextView = findViewById(R.id.activity_title) as TextView
    textView.text = "Paramlist is \n\n$paramListString"

    // to check if the url has specific keys
    if (sanitizer.hasParameter("type")) {
        val type = sanitizer.getValue("type")
        println("sanitizer has type param $type")
    }

0voto

Matthias Ronge Punkte 8421

Das scheint mir der beste Weg zu sein, um Ordnung zu schaffen:

static Map<String, String> decomposeQueryString(String query, Charset charset) {
    return Arrays.stream(query.split("&"))
        .map(pair -> pair.split("=", 2))
        .collect(Collectors.toMap(
            pair -> URLDecoder.decode(pair[0], charset),
            pair -> pair.length > 1 ? URLDecoder.decode(pair[1], charset) : null)
        );
}

Voraussetzung ist, dass Ihre Abfragesyntax keine wiederholten Parameter zulässt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X