1

I have a string url like this:

exampleUrl = www.example.com/test?item=param1=1&param2=11&param3=111&item=param1=2&param2=22&param3=222

and i want to extract from it a Map of key values using item as key.

I wrote the below function

fun String.getUrlParams(): Map<String, List<String>> {
    val params = HashMap<String, List<String>>()
    val urlParts = this.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
    if (urlParts.size > 1) {
        val query = urlParts[1]
        for (param in query.split("item=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
            System.out.println(param)
            val key = "item"
            var value = URLDecoder.decode(param, "UTF-8")
            var values: MutableList<String>? = params[key] as MutableList<String>?
            if (values == null) {
                values = ArrayList()
                params[key] = values as ArrayList<String>
            }
            values?.add(value)
        }

    }
    return params
}

But on printed data i am getting this -> {item=[, param1=1&param2=11&param3=111&, param1=2&param2=22&param3=222]}. It has an empty value on start and the & symbol on the end of second value.

The correct one should be -> {item=[param1=1&param2=11&param3=111, param1=2&param2=22&param3=222]}

What am i missing? Thanks in advance

1 Answer 1

3

Splitting on something that appears right at the start or end of a String will give you an empty String at the start or end of the results.

Instead of dropLastWhile you can filter all empty Strings.

You can use "&?item=" to avoid having the trailing & in your first block.

After removing the unnecessary toTypedArray() and Java-specific code you have:

fun String.getUrlParams(): Map<String, List<String>> {
    val params = HashMap<String, List<String>>()
    val urlParts = split("\\?".toRegex()).filter(String::isNotEmpty)
    if (urlParts.size > 1) {
        val query = urlParts[1]
        for (param in query.split("&?item=".toRegex()).filter(String::isNotEmpty)) {
            val key = "item"
            val value = URLDecoder.decode(param, "UTF-8")
            var values: MutableList<String>? = params[key] as MutableList<String>?
            if (values == null) {
                values = ArrayList()
                params[key] = values
            }
            values.add(value)
        }
    }
    return params
}

Cleaning it up a bit gives:

fun String.getUrlParams(): Map<String, List<String>> {
    val urlParts = split("\\?".toRegex()).filter(String::isNotEmpty)
    if (urlParts.size < 2) {
        return emptyMap()
    }
    val query = urlParts[1]
    return listOf("item").associateWith { key ->
        query.split("&?$key=".toRegex()).filter(String::isNotEmpty)
            .map { URLDecoder.decode(it, "UTF-8") }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.