2

I'm using a WebView in an Android app written in Kotlin to display some rich text content that is given via an API response. The data is given as raw text mixed with some HTML components (links) which is displayed in the app.

The goal of writing this Regex filter is to capture raw links not wrapped in <a> tags, and reformat them so that they are displayed richly in the web view.

My current attempts at solving this problem include using replace() with an inline function to capture the link and replace it with an <a> tag.

I have an overridden function which takes the data to be loaded into the WebView and adds some style data as well as removing any <iframe> tags. Those two components work, however my replacement using the pattern to match URLs does not have any effect.

Given a list:

http://example.com
https://example.com

I expect an output:

<a href="http://example.com">auto link</a>
<a href="https://example.com">auto link</a>

Yet my pattern yields unchanged input.

I am following a URL matching pattern found here: https://mathiasbynens.be/demo/url-regex


val pattern = "@(https?|ftp)://(-\\.)?([^\\s/?\\.#-]+\\.?)+(/[^\\s]*)?$@iS\n".toRegex()
data.replace(pattern) {
    "<a href=\"${it.groupValues[1]}\">auto link</a>"
}

Log.i("TEST", data)

This function fails to replace the data with the right link whenever I log it, even though I know that the pattern matches the links I am feeding it.

2
  • What is data? If it is an immutable string, assign a value to it. data = data.replace(pattern) { "<a href=\"${it.groupValues[1]}\">auto link</a>" } Commented Jun 7, 2019 at 20:51
  • Also, you are using a PHP-like formatted regex. In Kotlin, you should not use regex delimiters, in Kotlin, there are inline modifiers that you can use instead of flags. Commented Jun 7, 2019 at 20:55

2 Answers 2

1

Here is the sample code snippet that will do the job:

var data = "http://example.com <a href=\"http://example.com\">auto link</a>"
val pattern = """(?i)<a\s+[^>]*>[^<]*</a>|(https?|ftp)://(?:-\.)?([^\s/?.#-]+\.?)+(/\S*)?""".toRegex()
    data = data.replace(pattern) {
        if (it.groupValues[1].isNullOrEmpty()) it.value else "<a href=\"${it.value}\">auto link</a>" 
    }
println(data)

Output:

<a href="http://example.com">auto link</a> <a href="http://example.com">auto link</a>

See the Kotlin online demo

Note you need to assign a modified value back to data variable.

Also, you are using a PHP-like formatted regex, but in Kotlin, you should not use regex delimiters. Instead, you can use inline modifiers, like (?i) to make the pattern case insensitive.

Regex details

  • (?i) - case inbsensitive modifier
  • <a\s+[^>]*>[^<]*</a> - an A tag pattern
  • | - or
  • (https?|ftp) - Group 1, http, https or ftp
  • :// - a :// substring
  • (?:-\.)? - an optional -. substring
  • ([^\s/?.#-]+\.?)+ - one or more repetitions of 1 or more chars other than whitespace, /, ?, ., #, - and then an optional dot
  • (/\S*)? - an optional group, / followed with 0 or more non-whitespace chars.

If Group 1 matches, we replace with the link. Else, return the whole A tag back.

Sign up to request clarification or add additional context in comments.

Comments

0

I'm positive that there might be better ways to do this task, yet it seems we would be also validating, for which we would be starting with a simple expression:

^(https?:\/\/[^\s]+?\.[^\s]+)$

then we would add more constraints, if necessary, for validation and we would be replacing it with something similar to:

<a href="$1">auto link</a>

Demo

enter image description here

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.