Extract multiple integers from a String in Kotlin

Viewed 684

I have a single String in the following format(Output from Jsoup)

[<ul>
<li><span></span><a, rel="nofollow"><span>Afterword</span></a></li>
<li><span></span><a, rel="nofollow"><span>MW, Chapter, 2255</span></a></li>
<li><span></span><a, rel="nofollow"><span>MW, Chapter, 2254</span></a></li> 
<li><span></span><a, rel="nofollow"><span>MW, Chapter, 2253</span></a></li> 
<li><span></span><a, rel="nofollow"><span>MW, Chapter, 2252</span></a></li> 
</ul>]

I want to extract the integers such as 2255, 2254 etc from this String.

I used various options I found here but none of them worked. The solutions so far gives me just the digits all banded together.

I am open to use Jsoup or split for this.

Please help.

3 Answers

it is quite simple using regular expressions https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/

    val string = "[<ul>\n" +
            "<li><span></span><a, rel=\"nofollow\"><span>Afterword</span></a></li>\n" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2255</span></a></li>\n" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2254</span></a></li> \n" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2253</span></a></li> \n" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2252</span></a></li> \n" +
            "</ul>]"

    val regex = Regex("\\d+")
    val resultList = regex.findAll(string).map { it.value }.toList()
    println(resultList) //prints [2255, 2254, 2253, 2252]

I found a solution online which worked for me. sharing it here for others:

val p = Pattern.compile("\\d+")
val m = p.matcher(stringUnderTest)
while (m.find()) {
  println(m.group())
}

I tried extracting the text directly using JSoup but you're right in that everything just gets bunched together and you end up with a single string that includes everything which is less easy to work with.

Taking a step back then, you can instead get all the potentially relevant Elements using doc.select("ul li span"). From there, you can filter the elements which contain text starting with MW and then from there, take the text, split it, using ", " as a delimiter, to get an array and take the last element of the result (the integer). I parsed this to an Integer by wrapping the result using Integer.parseInt which you can remove if you just want the String value.

Finally the results that are filtered and mapped to the correct value are collected to a list.


import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;

import static java.util.stream.Collectors.toList;

public class JSoupExtract {

    public static final String input = "<ul>" +
            "<li><span></span><a, rel=\"nofollow\"><span>Afterword</span></a></li>" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2255</span></a></li>" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2254</span></a></li>" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2253</span></a></li>" +
            "<li><span></span><a, rel=\"nofollow\"><span>MW, Chapter, 2252</span></a></li>" +
            "</ul>";                       // TOKEN_ID = 0^  1^       2^
    public static final int INT_TOKEN_ID = 2;


    public static void main(String[] args) {
        Document doc = Jsoup.parse(input);
        Elements elements = doc.select("ul li span");
        List<Integer> result = elements.stream()
                .filter(e -> e.text() != null && e.text().startsWith("MW"))
                .map(e -> Integer.parseInt(e.text().split(", ")[INT_TOKEN_ID]))
                .collect(toList());

        System.out.println(result);
    }
}

output:

[2255, 2254, 2253, 2252]
Related