नाम-मान संग्रह में एक URI स्ट्रिंग को पार्स करें


274

मुझे इस तरह URI मिला है:

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

मुझे पार्स तत्वों के साथ एक संग्रह की आवश्यकता है:

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

सटीक होने के लिए, मुझे C # /। NET HttpUtility.ParseQueryString विधि के लिए जावा समकक्ष की आवश्यकता है ।

कृपया, मुझे इस पर एक सलाह दें।

धन्यवाद।



@MattBall यदि ओपी एंड्रॉइड का उपयोग कर रहा है, तो वह है
जुआन मेंडेस

156
क्या यह मनमौजी नहीं है कि यह java.net.URI/ के कोर एपीआई का हिस्सा नहीं है java.net.URL?
दिलुम रणतुंगा

कृपया इस समाधान की जाँच करें - पार्स और प्रारूप संचालन दोनों के लिए ठोस पुस्तकालय और कामकाजी उदाहरण: stackoverflow.com/a/37744000/1882064
arcseldon

जवाबों:


342

यदि आप बाहरी पुस्तकालय का उपयोग किए बिना इसे प्राप्त करने का एक तरीका ढूंढ रहे हैं, तो निम्न कोड आपकी सहायता करेगा।

public static Map<String, String> splitQuery(URL url) throws UnsupportedEncodingException {
    Map<String, String> query_pairs = new LinkedHashMap<String, String>();
    String query = url.getQuery();
    String[] pairs = query.split("&");
    for (String pair : pairs) {
        int idx = pair.indexOf("=");
        query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
    }
    return query_pairs;
}

आप लौटे हुए मानचित्र का उपयोग कर सकते हैं <map>.get("client_id"), आपके प्रश्न में दिए गए URL के साथ यह "SS" वापस आ जाएगा।

अद्यतन URL-डिकोडिंग जोड़ा गया

अद्यतन जैसा कि यह उत्तर अभी भी काफी लोकप्रिय है, मैंने ऊपर दिए गए विधि का एक उन्नत संस्करण बनाया है, जो एक ही कुंजी के साथ कई मापदंडों को संभालता है और साथ ही बिना मूल्य के पैरामीटर भी।

public static Map<String, List<String>> splitQuery(URL url) throws UnsupportedEncodingException {
  final Map<String, List<String>> query_pairs = new LinkedHashMap<String, List<String>>();
  final String[] pairs = url.getQuery().split("&");
  for (String pair : pairs) {
    final int idx = pair.indexOf("=");
    final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair;
    if (!query_pairs.containsKey(key)) {
      query_pairs.put(key, new LinkedList<String>());
    }
    final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null;
    query_pairs.get(key).add(value);
  }
  return query_pairs;
}

अद्यतन Java8 संस्करण

public Map<String, List<String>> splitQuery(URL url) {
    if (Strings.isNullOrEmpty(url.getQuery())) {
        return Collections.emptyMap();
    }
    return Arrays.stream(url.getQuery().split("&"))
            .map(this::splitQueryParameter)
            .collect(Collectors.groupingBy(SimpleImmutableEntry::getKey, LinkedHashMap::new, mapping(Map.Entry::getValue, toList())));
}

public SimpleImmutableEntry<String, String> splitQueryParameter(String it) {
    final int idx = it.indexOf("=");
    final String key = idx > 0 ? it.substring(0, idx) : it;
    final String value = idx > 0 && it.length() > idx + 1 ? it.substring(idx + 1) : null;
    return new SimpleImmutableEntry<>(key, value);
}

URL के साथ उपरोक्त विधि चलाना

https://stackoverflow.com?param1=value1&param2=&param3=value3&param3

यह नक्शा लौटाता है:

{param1=["value1"], param2=[null], param3=["value3", null]}

13
आप नाम और मापदंडों को डिकोड करना भूल रहे हैं, एक कारण यह है कि आमतौर पर पुस्तकालयों को सामान्य कार्य करने देना बेहतर होता है।
जुआन मेंडेस 20

10
वास्तव में, आप सही हैं ... लेकिन मैं व्यक्तिगत रूप से इस तरह के "आसान" कार्यों को लिखना पसंद करता हूं, इसके बजाय मुझे हर एक कार्य के लिए खुद की लाइब्रेरी का उपयोग करना होगा।
Pr0gr4mm3r 20

2
यदि आपके पास समान नाम / कुंजी के साथ कई पैरामीटर हैं, तो इस फ़ंक्शन का उपयोग करने से उस मान को ओवरराइड किया जाएगा जिसमें समान कुंजी है।
स्नोबॉल 147

4
@ क्रिस आप URL एन्कोडिंग के साथ भागने वाले xml / html को भ्रमित कर रहे हैं। आपका उदाहरण URL होना चाहिए: a.com/q?1=a%26b&2=b%26c
sceaj

3
यह इंगित करना अच्छा होगा कि कौन से फ़ंक्शंस का उपयोग किया जाता है: कलेक्टर।
टैपिंग

311

org.apache.http.client.utils.URLEncodedUtils

एक प्रसिद्ध पुस्तकालय है जो आपके लिए कर सकता है

import org.apache.hc.client5.http.utils.URLEncodedUtils

String url = "http://www.example.com/something.html?one=1&two=2&three=3&three=3a";

List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), Charset.forName("UTF-8"));

for (NameValuePair param : params) {
  System.out.println(param.getName() + " : " + param.getValue());
}

आउटपुट

one : 1
two : 2
three : 3
three : 3a

क्या मैं सभी तत्वों को पारित किए बिना इसके नाम से मूल्य प्राप्त कर सकता हूं? मेरा मतलब कुछ इस तरह है: System.out.print (params ["एक"]);
सेर्गेई शफीव

3
@SergeyShafiev यह जावा List<NameValuePair>में परिवर्तित करने के लिए तुच्छ है Map<String,String>, हैश मैप्स के लिए ब्रैकेट एक्सेस नहीं है, यह ऐसा लगेगा जैसे map.get("one")यदि आप नहीं जानते कि यह कैसे करना है, तो यह एक और सवाल होना चाहिए (लेकिन इसे अपने दम पर आज़माएं) । हम SO
जुआन मेंडेस

6
सावधान रहें कि यदि आपके URL में दो बार एक ही पैरामीटर है (यानी (a = 1 & a = 2) URLEncodedUtils एक IllegalArgumentException
Crystark

10
@ क्रिस्टार्क 4.3.3 httpclient के रूप में, डुप्लिकेट किए गए नामों के साथ क्वेरी स्ट्रिंग में कोई अपवाद नहीं है। यह उम्मीद के मुताबिक काम करता है। System.out.println(URLEncodedUtils.parse(new URI("http://example.com/?foo=bar&foo=baz"), "UTF-8"));प्रिंट करेगा [foo = bar, foo = baz]
अकिहिरो हर

4
Android 6 के रूप में, अपाचे HTTP क्लाइंट लाइब्रेरी को हटा दिया गया है। इसका अर्थ है URLEncodedUtils and NameValuePair` अब उपलब्ध नहीं है (जब तक कि आप यहाँ वर्णित विरासत अपाचे पुस्तकालय पर निर्भरता नहीं जोड़ते )।
टेड होप

108

यदि आप स्प्रिंग फ्रेमवर्क का उपयोग कर रहे हैं:

public static void main(String[] args) {
    String uri = "http://my.test.com/test?param1=ab&param2=cd&param2=ef";
    MultiValueMap<String, String> parameters =
            UriComponentsBuilder.fromUriString(uri).build().getQueryParams();
    List<String> param1 = parameters.get("param1");
    List<String> param2 = parameters.get("param2");
    System.out.println("param1: " + param1.get(0));
    System.out.println("param2: " + param2.get(0) + "," + param2.get(1));
}

तुम्हे मिल जाएगा:

param1: ab
param2: cd,ef

1
URL का उपयोग करने के लिएUriComponentsBuilder.fromHttpUrl(url)
22:55

51

Google अमरूद का उपयोग करें और इसे 2 लाइनों में करें:

import java.util.Map;
import com.google.common.base.Splitter;

public class Parser {
    public static void main(String... args) {
        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";
        String query = uri.split("\\?")[1];
        final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator('=').split(query);
        System.out.println(map);
    }
}

जो आपको देता है

{client_id=SS, response_type=code, scope=N_FULL, access_type=offline, redirect_uri=http://localhost/Callback}

18
चयनित उत्तर में वर्णित URL डिकोडिंग के बारे में क्या?
क्लिंट ईस्टवुड

7
यह एक ही नाम के साथ कई कुंजियों के लिए भी संदिग्ध है।
Javadocs के

5
मैन्युअल रूप से बंटवारे के बजाय uriआपको इसका उपयोग करना चाहिए new java.net.URL(uri).getQuery()क्योंकि यह आपको URL पर मुफ्त इनपुट सत्यापन प्रदान करता है।
एवग्स्टव्स

1
डिकोडिंग के लिए: अंतिम मानचित्र <स्ट्रिंग, स्ट्रिंग> क्वेरीवार्स = मैप्स। ट्रांसफॉर्मफॉर्मवेल्यूज़ (नक्शा, नया फ़ंक्शन <स्ट्रिंग, स्ट्रिंग> () {@ ओवरराइड सार्वजनिक स्ट्रिंग लागू करें (स्ट्रिंग मान) {कोशिश {रिटर्न डीडीकोडकोड (मान, "UTF- 8 ");} कैच (UnsupportedEncodingException e) {// TODO ऑटो-जनरेट कैच ब्लॉक e.printStackTrace ();} रिटर्न वैल्यू;}});
फ़्रेकेहेड जूल 22'15

11
चेतावनी !! अगर यह क्वेरी स्ट्रिंग में डुप्लिकेट कुंजी है, तो splitter.split()इसे फेंकना सुरक्षित नहीं है IllegalArgumentException। देखें stackoverflow.com/questions/1746507/...
एंडरसन

31

सबसे छोटा रास्ता मैंने पाया है यह एक है:

MultiValueMap<String, String> queryParams =
            UriComponentsBuilder.fromUriString(url).build().getQueryParams();

अद्यतन: UriComponentsBuilder वसंत से आता है। यहाँ लिंक है


3
यह जानने के बिना कि यह UriCompordsBuilder वर्ग कहाँ से आता है, यह बहुत उपयोगी नहीं है।
थॉमस मॉर्टगैन

3
यह ध्यान देने योग्य हो सकता है कि यह केवल एक अच्छा विचार है यदि आप पहले से ही स्प्रिंग का उपयोग कर रहे हैं। यदि आप स्प्रिंग का उपयोग नहीं कर रहे हैं, तो आप बचना चाहेंगे। samatkinson.com/why-i-hate-spring
निक

1
NB यह URIs लेता है। यूआरआई का जावा का संस्करण यूआरएल का सुपरसेट नहीं है (यही कारण है कि टूरी अपवादों को फेंक सकता है)।
एडम जेंट

18

Android के लिए, यदि आप अपने प्रोजेक्ट में OkHttp का उपयोग कर रहे हैं । आपको इस पर एक नज़र पड़ सकती है। यह सरल और सहायक है।

final HttpUrl url = HttpUrl.parse(query);
if (url != null) {
    final String target = url.queryParameter("target");
    final String id = url.queryParameter("id");
}

HttpUrl एक अजीब नाम है, लेकिन यह वही है जो मुझे चाहिए था। धन्यवाद।
गुइसिम

10

जावा 8 एक बयान

विश्लेषण करने के लिए URL दिया:

URL url = new URL("https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback");

यह समाधान जोड़े की एक सूची एकत्र करता है:

List<AbstractMap.SimpleEntry<String, String>> list = 
        Pattern.compile("&").splitAsStream(url.getQuery())
        .map(s -> Arrays.copyOf(s.split("="), 2))
        .map(o -> new AbstractMap.SimpleEntry<String, String>(decode(o[0]), decode(o[1])))
        .collect(toList());

दूसरी ओर यह समाधान एक नक्शा एकत्र करता है (यह देखते हुए कि एक यूआरएल में एक ही नाम के साथ अधिक पैरामीटर हो सकते हैं लेकिन अलग-अलग मान हैं)।

Map<String, List<String>> list = 
        Pattern.compile("&").splitAsStream(url.getQuery())
        .map(s -> Arrays.copyOf(s.split("="), 2))
        .collect(groupingBy(s -> decode(s[0]), mapping(s -> decode(s[1]), toList())));

दोनों समाधानों को ठीक से पैरामीटर को डीकोड करने के लिए एक उपयोगिता फ़ंक्शन का उपयोग करना चाहिए।

private static String decode(final String encoded) {
    try {
        return encoded == null ? null : URLDecoder.decode(encoded, "UTF-8");
    } catch(final UnsupportedEncodingException e) {
        throw new RuntimeException("Impossible: UTF-8 is a required encoding", e);
    }
}

4
यह जावा 8 ऑनलाइनर के बजाय एक जावा 8 दृष्टिकोण है
Stephan

@Stephan अच्छी तरह से :) शायद दोनों। लेकिन मुझे यह समझने में अधिक दिलचस्पी है कि क्या आपको यह समाधान पसंद है।
मुक्तदेव

3
IMO, एक ऑनलाइनर छोटा होना चाहिए और कई लाइनों पर नहीं होना चाहिए।
Stephan

1
इसमें कई कथन शामिल हैं।
Stephan

2
मुझे लगता है कि आप एक ही लाइन पर एक पूरी कक्षा लिख ​​सकते हैं, लेकिन ऐसा नहीं है जो आमतौर पर "वन-लाइनर" वाक्यांश से होता है।
अभिजीत सरकार

10

यदि आप सर्वलेट doGet का उपयोग कर रहे हैं तो यह प्रयास करें

request.getParameterMap()

इस अनुरोध के मापदंडों का एक java.util.Map लौटाता है।

रिटर्न: एक अपरिवर्तनीय java.util.ap जिसमें पैरामीटर नाम कुंजी के रूप में और पैरामीटर मान मानचित्र मान के रूप में होते हैं। पैरामीटर मैप में कुंजियाँ टाइप स्ट्रिंग की होती हैं। पैरामीटर मैप में मान स्ट्रिंग स्ट्रिंग के प्रकार हैं।

( जावा डॉक्टर )


यह स्प्रिंग वेब के साथ-साथ आपके नियंत्रक में काम करता है जिसमें आपके पास एक प्रकार का पैरामीटर हो सकता है HttpServletRequestऔर यह MockHttpServletRequestमॉक एमवीसी इकाई परीक्षणों में भी काम करता है ।
गेमशैल

8

यदि आप जावा 8 का उपयोग कर रहे हैं और आप कुछ पुन: प्रयोज्य विधियों को लिखने के लिए तैयार हैं, तो आप इसे एक पंक्ति में कर सकते हैं।

private Map<String, List<String>> parse(final String query) {
    return Arrays.asList(query.split("&")).stream().map(p -> p.split("=")).collect(Collectors.toMap(s -> decode(index(s, 0)), s -> Arrays.asList(decode(index(s, 1))), this::mergeLists));
}

private <T> List<T> mergeLists(final List<T> l1, final List<T> l2) {
    List<T> list = new ArrayList<>();
    list.addAll(l1);
    list.addAll(l2);
    return list;
}

private static <T> T index(final T[] array, final int index) {
    return index >= array.length ? null : array[index];
}

private static String decode(final String encoded) {
    try {
        return encoded == null ? null : URLDecoder.decode(encoded, "UTF-8");
    } catch(final UnsupportedEncodingException e) {
        throw new RuntimeException("Impossible: UTF-8 is a required encoding", e);
    }
}

लेकिन यह एक बहुत क्रूर रेखा है।


3

Android पर, पैकेज Android.net में एक Uri वर्ग है । ध्यान दें कि Uri android.net का हिस्सा है , जबकि URI java.net का हिस्सा है ।

उरी वर्ग में क्वेरी से कुंजी-मूल्य जोड़े निकालने के लिए कई कार्य हैं। यहां छवि विवरण दर्ज करें

निम्नलिखित फ़ंक्शन हैशपॉप के रूप में कुंजी-मूल्य जोड़े देता है।

जावा में:

Map<String, String> getQueryKeyValueMap(Uri uri){
    HashMap<String, String> keyValueMap = new HashMap();
    String key;
    String value;

    Set<String> keyNamesList = uri.getQueryParameterNames();
    Iterator iterator = keyNamesList.iterator();

    while (iterator.hasNext()){
        key = (String) iterator.next();
        value = uri.getQueryParameter(key);
        keyValueMap.put(key, value);
    }
    return keyValueMap;
}

कोटलिन में:

fun getQueryKeyValueMap(uri: Uri): HashMap<String, String> {
        val keyValueMap = HashMap<String, String>()
        var key: String
        var value: String

        val keyNamesList = uri.queryParameterNames
        val iterator = keyNamesList.iterator()

        while (iterator.hasNext()) {
            key = iterator.next() as String
            value = uri.getQueryParameter(key) as String
            keyValueMap.put(key, value)
        }
        return keyValueMap
    }

2

उपर्युक्त टिप्पणियों और समाधानों का उपयोग करते हुए, मैं मैप <स्ट्रींग, ऑब्जेक्ट> का उपयोग करके सभी क्वेरी मापदंडों को संग्रहीत कर रहा हूं जहां ऑब्जेक्ट या तो स्ट्रिंग हो सकते हैं या <स्ट्रींग> सेट कर सकते हैं। समाधान नीचे दिया गया है। पहले url को मान्य करने के लिए किसी प्रकार के url सत्यापनकर्ता का उपयोग करने की अनुशंसा की जाती है और फिर ConvertQueryStringToMap विधि को कॉल करें।

private static final String DEFAULT_ENCODING_SCHEME = "UTF-8";

public static Map<String, Object> convertQueryStringToMap(String url) throws UnsupportedEncodingException, URISyntaxException {
    List<NameValuePair> params = URLEncodedUtils.parse(new URI(url), DEFAULT_ENCODING_SCHEME);
    Map<String, Object> queryStringMap = new HashMap<>();
    for(NameValuePair param : params){
        queryStringMap.put(param.getName(), handleMultiValuedQueryParam(queryStringMap, param.getName(), param.getValue()));
    }
    return queryStringMap;
}

private static Object handleMultiValuedQueryParam(Map responseMap, String key, String value) {
    if (!responseMap.containsKey(key)) {
        return value.contains(",") ? new HashSet<String>(Arrays.asList(value.split(","))) : value;
    } else {
        Set<String> queryValueSet = responseMap.get(key) instanceof Set ? (Set<String>) responseMap.get(key) : new HashSet<String>();
        if (value.contains(",")) {
            queryValueSet.addAll(Arrays.asList(value.split(",")));
        } else {
            queryValueSet.add(value);
        }
        return queryValueSet;
    }
}

2

मुझे कोटलिन संस्करण में यह देखना था कि यह Google में शीर्ष परिणाम कैसे है।

@Throws(UnsupportedEncodingException::class)
fun splitQuery(url: URL): Map<String, List<String>> {

    val queryPairs = LinkedHashMap<String, ArrayList<String>>()

    url.query.split("&".toRegex())
            .dropLastWhile { it.isEmpty() }
            .map { it.split('=') }
            .map { it.getOrEmpty(0).decodeToUTF8() to it.getOrEmpty(1).decodeToUTF8() }
            .forEach { (key, value) ->

                if (!queryPairs.containsKey(key)) {
                    queryPairs[key] = arrayListOf(value)
                } else {

                    if(!queryPairs[key]!!.contains(value)) {
                        queryPairs[key]!!.add(value)
                    }
                }
            }

    return queryPairs
}

और विस्तार के तरीके

fun List<String>.getOrEmpty(index: Int) : String {
    return getOrElse(index) {""}
}

fun String.decodeToUTF8(): String { 
    URLDecoder.decode(this, "UTF-8")
}

1
समान क्रेडिट करने के लिए stackoverflow.com/users/1203812/matthew-herod 50/50 प्रयास लेकिन सह लेखक नहीं कर सकता।
ग्राहम स्मिथ

2

URI क्वेरी भाग (incl। डिकोडिंग और मल्टी पैरामीटर मान) के डिकोडिंग के लिए एक तैयार-से-उपयोग समाधान

टिप्पणियाँ

मैं https://stackoverflow.com/a/135925673.1082 पर @ Pr0gr4mm3r द्वारा प्रदान किए गए कोड से खुश नहीं था । स्ट्रीम-आधारित समाधान URLDecoding, उत्परिवर्तित संस्करण क्लैंपसी नहीं करता है।

इस प्रकार मैं एक समाधान विस्तृत है कि

  • URI क्वेरी भाग को एक में विघटित कर सकता है Map<String, List<Optional<String>>>
  • एक ही पैरामीटर नाम के लिए कई मानों को संभाल सकते हैं
  • बिना मान के पैरामीटर का सही तरीके से प्रतिनिधित्व कर सकते हैं ( Optional.empty()इसके बजाय null)
  • पैरामीटर नाम और मानों को सही तरीके से घटाता हैURLdecode
  • जावा 8 स्ट्रीम पर आधारित है
  • सीधे प्रयोग करने योग्य है (नीचे आयात सहित कोड देखें)
  • उचित त्रुटि से निपटने की अनुमति देता है (यहां एक चेक अपवाद UnsupportedEncodingExceptionको रनटाइम अपवाद में बदलकर RuntimeUnsupportedEncodingExceptionस्ट्रीम के साथ इंटरप्ले की अनुमति देता है। चेक किए गए अपवादों को फेंकने वाले फ़ंक्शन में नियमित फ़ंक्शन को लपेटना एक दर्द है। और Tryजावा भाषा डिफ़ॉल्ट में स्काला उपलब्ध नहीं है।)

जावा कोड

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import static java.util.stream.Collectors.*;

public class URIParameterDecode {
    /**
     * Decode parameters in query part of a URI into a map from parameter name to its parameter values.
     * For parameters that occur multiple times each value is collected.
     * Proper decoding of the parameters is performed.
     * 
     * Example
     *   <pre>a=1&b=2&c=&a=4</pre>
     * is converted into
     *   <pre>{a=[Optional[1], Optional[4]], b=[Optional[2]], c=[Optional.empty]}</pre>
     * @param query the query part of an URI 
     * @return map of parameters names into a list of their values.
     *         
     */
    public static Map<String, List<Optional<String>>> splitQuery(String query) {
        if (query == null || query.isEmpty()) {
            return Collections.emptyMap();
        }

        return Arrays.stream(query.split("&"))
                    .map(p -> splitQueryParameter(p))
                    .collect(groupingBy(e -> e.get0(), // group by parameter name
                            mapping(e -> e.get1(), toList())));// keep parameter values and assemble into list
    }

    public static Pair<String, Optional<String>> splitQueryParameter(String parameter) {
        final String enc = "UTF-8";
        List<String> keyValue = Arrays.stream(parameter.split("="))
                .map(e -> {
                    try {
                        return URLDecoder.decode(e, enc);
                    } catch (UnsupportedEncodingException ex) {
                        throw new RuntimeUnsupportedEncodingException(ex);
                    }
                }).collect(toList());

        if (keyValue.size() == 2) {
            return new Pair(keyValue.get(0), Optional.of(keyValue.get(1)));
        } else {
            return new Pair(keyValue.get(0), Optional.empty());
        }
    }

    /** Runtime exception (instead of checked exception) to denote unsupported enconding */
    public static class RuntimeUnsupportedEncodingException extends RuntimeException {
        public RuntimeUnsupportedEncodingException(Throwable cause) {
            super(cause);
        }
    }

    /**
     * A simple pair of two elements
     * @param <U> first element
     * @param <V> second element
     */
    public static class Pair<U, V> {
        U a;
        V b;

        public Pair(U u, V v) {
            this.a = u;
            this.b = v;
        }

        public U get0() {
            return a;
        }

        public V get1() {
            return b;
        }
    }
}

स्काला कोड

... और पूर्णता के लिए मैं स्केल में समाधान प्रदान करने का विरोध नहीं कर सकता जो संक्षिप्तता और सुंदरता पर हावी है

import java.net.URLDecoder

object Decode {
  def main(args: Array[String]): Unit = {
    val input = "a=1&b=2&c=&a=4";
    println(separate(input))
  }

  def separate(input: String) : Map[String, List[Option[String]]] = {
    case class Parameter(key: String, value: Option[String])

    def separateParameter(parameter: String) : Parameter =
      parameter.split("=")
               .map(e => URLDecoder.decode(e, "UTF-8")) match {
      case Array(key, value) =>  Parameter(key, Some(value))
      case Array(key) => Parameter(key, None)
    }

    input.split("&").toList
      .map(p => separateParameter(p))
      .groupBy(p => p.key)
      .mapValues(vs => vs.map(p => p.value))
  }
}

1

जावा 8 संस्करण के लिए बस एक अद्यतन

public Map<String, List<String>> splitQuery(URL url) {
    if (Strings.isNullOrEmpty(url.getQuery())) {
        return Collections.emptyMap();
    }
    return Arrays.stream(url.getQuery().split("&"))
            .map(this::splitQueryParameter)
            .collect(Collectors.groupingBy(SimpleImmutableEntry::getKey, LinkedHashMap::new, **Collectors**.mapping(Map.Entry::getValue, **Collectors**.toList())));
}

मैपिंग और टॉलिस्ट () विधियों का उपयोग उन कलेक्टरों के साथ किया जाना चाहिए, जिनका शीर्ष उत्तर में उल्लेख नहीं किया गया था। अन्यथा यह आईडीई में संकलन त्रुटि को फेंक देगा


लगता है कि आपको अपनी splitQueryParameters()विधि भी साझा करने की आवश्यकता है ? और क्या साथ है **Collectors**?
किर्बी

1

Https://stackoverflow.com/a/51024552/3286489 से प्रारंभिक संदर्भ के साथ कोटलिन का उत्तर , लेकिन कोड को सुधारने से बेहतर संस्करण के साथ और इसके 2 संस्करण प्रदान करता है, और अपरिवर्तनीय संग्रह संचालन का उपयोग करता है

java.net.URIक्वेरी निकालने के लिए उपयोग करें । फिर नीचे दिए गए विस्तार कार्यों का उपयोग करें

  1. मान लें कि आप केवल क्वेरी का अंतिम मान चाहते हैं, अर्थात , नीचे दिए गए एक्सटेंशन फ़ंक्शन का उपयोग page2&page3करेंगे{page=3}
    fun URI.getQueryMap(): Map<String, String> {
        if (query == null) return emptyMap()

        return query.split("&")
                .mapNotNull { element -> element.split("=")
                        .takeIf { it.size == 2 && it.none { it.isBlank() } } }
                .associateBy({ it[0].decodeUTF8() }, { it[1].decodeUTF8() })
    }

    private fun String.decodeUTF8() = URLDecoder.decode(this, "UTF-8") // decode page=%22ABC%22 to page="ABC"
  1. मान लें कि आप क्वेरी के लिए सभी मानों की एक सूची चाहते page2&page3हैं{page=[2, 3]}
    fun URI.getQueryMapList(): Map<String, List<String>> {
        if (query == null) return emptyMap()

        return query.split("&")
                .distinct()
                .mapNotNull { element -> element.split("=")
                        .takeIf { it.size == 2 && it.none { it.isBlank() } } }
                .groupBy({ it[0].decodeUTF8() }, { it[1].decodeUTF8() })
    }

    private fun String.decodeUTF8() = URLDecoder.decode(this, "UTF-8") // decode page=%22ABC%22 to page="ABC"

नीचे के रूप में इसका उपयोग करने का तरीका

    val uri = URI("schema://host/path/?page=&page=2&page=2&page=3")
    println(uri.getQueryMapList()) // Result is {page=[2, 3]}
    println(uri.getQueryMap()) // Result is {page=3}

1

Netty नामक एक अच्छा क्वेरी स्ट्रिंग पार्सर भी प्रदान करता है QueryStringDecoder। कोड की एक पंक्ति में, यह प्रश्न में URL को पार्स कर सकता है। मुझे पसंद है क्योंकि इसे पकड़ने या फेंकने की आवश्यकता नहीं है java.net.MalformedURLException

एक पंक्ति में:

Map<String, List<String>> parameters = new QueryStringDecoder(url).parameters();

यहाँ javadocs देखें: https://netty.io/4.1/api/io/netty/handler/codec/http/QueryStringDecoder.html

यहाँ एक छोटा, आत्म निहित, सही उदाहरण है:

import io.netty.handler.codec.http.QueryStringDecoder;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;

public class UrlParse {

  public static void main(String... args) {
    String url = "https://google.com.ua/oauth/authorize?client_id=SS&response_type=code&scope=N_FULL&access_type=offline&redirect_uri=http://localhost/Callback";
    QueryStringDecoder decoder = new QueryStringDecoder(url);
    Map<String, List<String>> parameters = decoder.parameters();
    print(parameters);
  }

  private static void print(final Map<String, List<String>> parameters) {
    System.out.println("NAME               VALUE");
    System.out.println("------------------------");
    parameters.forEach((key, values) ->
        values.forEach(val ->
            System.out.println(StringUtils.rightPad(key, 19) + val)));
  }
}

जो उत्पन्न करता है

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

0

यहाँ उत्तर देना क्योंकि यह एक लोकप्रिय धागा है। यह कोटलिन में एक साफ समाधान है जो अनुशंसित UrlQuerySanitizerएपीआई का उपयोग करता है । आधिकारिक दस्तावेज देखें । मैंने पैरामन्स को समेटने और प्रदर्शित करने के लिए एक स्ट्रिंग बिल्डर जोड़ा है।

    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")
    }

0

यहाँ मेरा समाधान कम और वैकल्पिक के साथ है :

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;
}
  • मैं डुप्लिकेट मापदंडों की उपेक्षा करता हूं (मैं पिछले एक को लेता हूं)।
  • मैं Optional<SimpleImmutableEntry<String, String>>बाद में कचरे को अनदेखा करने के लिए उपयोग करता हूं
  • कमी एक खाली मानचित्र के साथ शुरू होती है, फिर प्रत्येक SimpleImmutableEntry पर इसे आबाद करें

यदि आप पूछते हैं, तो कम करने के लिए अंतिम पैरामीटर में इस अजीब कंघी की आवश्यकता होती है, जिसका उपयोग केवल समानांतर धाराओं में किया जाता है। इसका लक्ष्य दो मध्यवर्ती परिणाम (यहां हैशपॅप) को मर्ज करना है।


-1

यदि आप स्प्रिंग का उपयोग कर रहे हैं, तो @RequestParam Map<String,String> अपने नियंत्रक विधि में टाइप का एक तर्क जोड़ें , और स्प्रिंग आपके लिए मानचित्र का निर्माण करेगा!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.