25

In Java I have:

String params = "depCity=PAR&roomType=D&depCity=NYC";

I want to get values of depCity parameters (PAR,NYC).

So I created regex:

String regex = "depCity=([^&]+)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(params);

m.find() is returning false. m.groups() is returning IllegalArgumentException.

What am I doing wrong?

VLAZ
  • 26,331
  • 9
  • 49
  • 67
gospodin
  • 1,133
  • 4
  • 22
  • 42
  • Possible duplicate of [Parse a URI String into Name-Value Collection](https://stackoverflow.com/questions/13592236/parse-a-uri-string-into-name-value-collection) – Oleg Estekhin Nov 17 '17 at 13:52

7 Answers7

43

It doesn't have to be regex. Since I think there's no standard method to handle this thing, I'm using something that I copied from somewhere (and perhaps modified a bit):

public static Map<String, List<String>> getQueryParams(String url) {
    try {
        Map<String, List<String>> params = new HashMap<String, List<String>>();
        String[] urlParts = url.split("\\?");
        if (urlParts.length > 1) {
            String query = urlParts[1];
            for (String param : query.split("&")) {
                String[] pair = param.split("=");
                String key = URLDecoder.decode(pair[0], "UTF-8");
                String value = "";
                if (pair.length > 1) {
                    value = URLDecoder.decode(pair[1], "UTF-8");
                }

                List<String> values = params.get(key);
                if (values == null) {
                    values = new ArrayList<String>();
                    params.put(key, values);
                }
                values.add(value);
            }
        }

        return params;
    } catch (UnsupportedEncodingException ex) {
        throw new AssertionError(ex);
    }
}

So, when you call it, you will get all parameters and their values. The method handles multi-valued params, hence the List<String> rather than String, and in your case you'll need to get the first list element.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • This solution is also working, but personally I'm not a fan of Maps - I try to use solutions that are more simple. But thanks anyway! – gospodin May 06 '11 at 08:36
  • 9
    Maps are a very core and simple concept, so I don't see an issue with them. – Bozho May 06 '11 at 08:38
  • 3
    This solution does not regard the fragment part of an URL which is appended on the end after a "#". In http urls this part references an internal anchor. So the variable query must be split again at "#" and then the index 0 of the returned array must be further processed. – haferblues Oct 31 '12 at 08:56
  • 5
    the part after # is not submitted to the server – Bozho Oct 31 '12 at 20:18
  • may I ask why its is a `Map>` and not a `Map` ? – Zapnologica Aug 18 '15 at 12:56
  • 1
    It will raise an ArrayIndexOutOfBoundException for corner cases such as "/foo?=" – Guido Aug 24 '16 at 21:34
17

I have three solutions, the third one is an improved version of Bozho's.

First, if you don't want to write stuff yourself and simply use a lib, then use Apache's httpcomponents lib's URIBuilder class: http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/URIBuilder.html

new URIBuilder("http://...").getQueryParams()...

Second:

// overwrites duplicates
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
public static Map<String, String> readParamsIntoMap(String url, String charset) throws URISyntaxException {
    Map<String, String> params = new HashMap<>();

    List<NameValuePair> result = URLEncodedUtils.parse(new URI(url), charset);

    for (NameValuePair nvp : result) {
        params.put(nvp.getName(), nvp.getValue());
    }

    return params;
}

Third:

public static Map<String, List<String>> getQueryParams(String url) throws UnsupportedEncodingException {
    Map<String, List<String>> params = new HashMap<String, List<String>>();
    String[] urlParts = url.split("\\?");
    if (urlParts.length < 2) {
        return params;
    }

    String query = urlParts[1];
    for (String param : query.split("&")) {
        String[] pair = param.split("=");
        String key = URLDecoder.decode(pair[0], "UTF-8");
        String value = "";
        if (pair.length > 1) {
            value = URLDecoder.decode(pair[1], "UTF-8");
        }

        // skip ?& and &&
        if ("".equals(key) && pair.length == 1) {
            continue;
        }

        List<String> values = params.get(key);
        if (values == null) {
            values = new ArrayList<String>();
            params.put(key, values);
        }
        values.add(value);
    }

    return params;
}
Community
  • 1
  • 1
user1050755
  • 11,218
  • 4
  • 45
  • 56
17

Not sure how you used find and group, but this works fine:

String params = "depCity=PAR&roomType=D&depCity=NYC";

try {
    Pattern p = Pattern.compile("depCity=([^&]+)");
    Matcher m = p.matcher(params);
    while (m.find()) {
        System.out.println(m.group());
    } 
} catch (PatternSyntaxException ex) {
    // error handling
}

However, If you only want the values, not the key depCity= then you can either use m.group(1) or use a regex with lookarounds:

Pattern p = Pattern.compile("(?<=depCity=).*?(?=&|$)");

It works in the same Java code as above. It tries to find a start position right after depCity=. Then matches anything but as little as possible until it reaches a point facing & or end of input.

Staffan Nöteberg
  • 4,095
  • 1
  • 19
  • 17
  • 1
    Just a small remark: instead of using complicating pattern "(?<=depCity=).*?(?=&|$)" to get only values, Im using the first soluiton "depCity=([^&]+)" in combination with m.group(1) to get only values. – gospodin May 06 '11 at 08:55
10

If you are developing an Android application, try this:

String yourParam = null;
Uri uri = Uri.parse(url);
try {
    yourParam = URLDecoder.decode(uri.getQueryParameter(PARAM_NAME), "UTF-8");
} catch (UnsupportedEncodingException exception) {
    exception.printStackTrace();
}        
Peter V. Mørch
  • 13,830
  • 8
  • 69
  • 103
Mikhail Valuyskiy
  • 1,238
  • 2
  • 16
  • 31
8

If spring-web is present on classpath, UriComponentsBuilder can be used.

MultiValueMap<String, String> queryParams =
            UriComponentsBuilder.fromUriString(url).build().getQueryParams();
qza
  • 599
  • 4
  • 7
2

Simple Solution create the map out of all param name and values and use it :).

import org.apache.commons.lang3.StringUtils;

    public String splitURL(String url, String parameter){
                HashMap<String, String> urlMap=new HashMap<String, String>();
                String queryString=StringUtils.substringAfter(url,"?");
                for(String param : queryString.split("&")){
                    urlMap.put(StringUtils.substringBefore(param, "="),StringUtils.substringAfter(param, "="));
                }
                return urlMap.get(parameter);
            }
manish Prasad
  • 636
  • 6
  • 16
0

same but with jsonobject:

public static JSONObject getQueryParams2(String url) {
    JSONObject json = new JSONObject();
    try {
        String[] urlParts = url.split("\\?");
        JSONArray array = new  JSONArray();
        if (urlParts.length > 1) {
            String query = urlParts[1];
            for (String param : query.split("&")) {
                String[] pair = param.split("=");
                String key = URLDecoder.decode(pair[0], "UTF-8");
                String value = "";
                if (pair.length > 1) {
                    value = URLDecoder.decode(pair[1], "UTF-8");
                    if(json.has(key)) {
                        array = json.getJSONArray(key);
                        array.put(value);
                        json.put(key, array);
                        array = new JSONArray();
                    } else {
                        array.put(value);
                        json.put(key, array);
                        array = new JSONArray();
                    }
                }
            }
        }
        return json;
    } catch (Exception ex) {
        throw new AssertionError(ex);
    }
}