Skip to content

Instantly share code, notes, and snippets.

@ForceTower
Created September 25, 2023 12:26
Show Gist options
  • Save ForceTower/c061d0527ed370ea1ae548d283cb14f7 to your computer and use it in GitHub Desktop.
Save ForceTower/c061d0527ed370ea1ae548d283cb14f7 to your computer and use it in GitHub Desktop.
import android.graphics.Typeface
import android.text.SpannableString
import android.text.Spanned
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
private val BOLD_REGEX = Regex("\\*([^*]+)\\*")
private val ITALIC_REGEX = Regex("_([^_]+)_")
private val STRIKE_REGEX = Regex("~([^~]+)~")
private val UNDERLINE_REGEX = Regex("#([^#]+)#")
private val EFFECT_REGEX_LIST = listOf(BOLD_REGEX, ITALIC_REGEX, STRIKE_REGEX, UNDERLINE_REGEX)
private data class EffectIndex(val start: Int, val end: Int, val type: Int)
private fun spanByType(type: Int): Any {
return when (type) {
0 -> StyleSpan(Typeface.BOLD)
1 -> StyleSpan(Typeface.ITALIC)
2 -> StrikethroughSpan()
3 -> UnderlineSpan()
else -> throw IllegalStateException("unknown type")
}
}
fun String?.nullIfBlank(): String? {
return if (isNullOrBlank()) null else this
}
fun String.createSpannable(): SpannableString {
val values = EFFECT_REGEX_LIST.flatMapIndexed { type, regex ->
val matches = regex.findAll(this)
matches.map { result ->
val range = result.groups[1]?.range ?: throw IllegalStateException("no match at regex?")
EffectIndex(range.first - 1, range.last + 1, type)
}
}
val indices = values.flatMap { listOf(it.start, it.end) }.distinct().sorted()
fun indexedPosition(index: Int): Int {
val position = indices.indexOf(index)
return index - position
}
val finalString = this
.replace(BOLD_REGEX, "$1")
.replace(ITALIC_REGEX, "$1")
.replace(STRIKE_REGEX, "$1")
.replace(UNDERLINE_REGEX, "$1")
val spannable = SpannableString(finalString).apply {
values.forEach { effect ->
val span = spanByType(effect.type)
setSpan(span, indexedPosition(effect.start), indexedPosition(effect.end), Spanned.SPAN_INCLUSIVE_INCLUSIVE)
}
}
return spannable
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment