1 changed files with 34 additions and 0 deletions
@ -0,0 +1,34 @@
|
||||
package com.utun.chat.data |
||||
|
||||
import java.net.URI |
||||
|
||||
/** Границы UTF-16 и полный адрес; разбор не меняет текст и не открывает ссылки. */ |
||||
data class MessageLink(val start: Int, val end: Int, val url: String) |
||||
|
||||
object MessageLinks { |
||||
private val pattern = Regex("utun://[A-Za-z0-9+/]+={0,2}|(?i:https?://)[^\\s\\p{Z}\\p{Cc}<>\"'`«»“”‘’]+") |
||||
|
||||
/** Некорректные URL в пользовательском тексте остаются обычным текстом. */ |
||||
fun isWebUrl(url: String): Boolean = try { |
||||
val uri = URI(url) |
||||
(uri.scheme.equals("http", true) || uri.scheme.equals("https", true)) && |
||||
uri.toURL().let { it.host.isNotEmpty() && it.port in -1..65535 } |
||||
} catch (_: IllegalArgumentException) { false } |
||||
catch (_: java.net.URISyntaxException) { false } |
||||
catch (_: java.net.MalformedURLException) { false } |
||||
|
||||
fun parse(text: String): List<MessageLink> = pattern.findAll(text).mapNotNull { match -> |
||||
var url = match.value |
||||
if (!url.startsWith("utun://")) { |
||||
while (url.isNotEmpty()) { |
||||
val last = url.last() |
||||
val closing = ")]}".indexOf(last) |
||||
val unmatched = closing >= 0 && url.count { it == last } > url.count { it == "([{"[closing] } |
||||
if (last !in ".,;:!?" && !unmatched) break |
||||
url = url.dropLast(1) |
||||
} |
||||
if (!isWebUrl(url)) return@mapNotNull null |
||||
} |
||||
MessageLink(match.range.first, match.range.first + url.length, url) |
||||
}.toList() |
||||
} |
||||
Loading…
Reference in new issue