Issue
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.
Solution
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,httpsorftp://- 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.
Answered By - Wiktor Stribiżew
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.