72 lines
2.4 KiB
Kotlin
72 lines
2.4 KiB
Kotlin
package space.bloggin.vellum
|
|
|
|
/**
|
|
* Verse markup: {words|H430} Strong's group, [words] translator italics, <words> words of Jesus.
|
|
*/
|
|
object Markup {
|
|
data class Seg(val text: String, val jesus: Boolean, val italic: Boolean, val strong: String?)
|
|
|
|
fun parse(s: String): List<Seg> {
|
|
val out = ArrayList<Seg>()
|
|
var jesus = false
|
|
var italic = false
|
|
val buf = StringBuilder()
|
|
fun flush(strong: String? = null) {
|
|
if (buf.isNotEmpty()) {
|
|
out.add(Seg(buf.toString(), jesus, italic, strong)); buf.clear()
|
|
}
|
|
}
|
|
var i = 0
|
|
while (i < s.length) {
|
|
when (val ch = s[i]) {
|
|
'<' -> { flush(); jesus = true }
|
|
'>' -> { flush(); jesus = false }
|
|
'[' -> { flush(); italic = true }
|
|
']' -> { flush(); italic = false }
|
|
'{' -> {
|
|
flush()
|
|
val bar = s.indexOf('|', i)
|
|
val close = s.indexOf('}', i)
|
|
if (bar in (i + 1) until close) {
|
|
// the word itself may contain [ ] italics in rare cases; strip them
|
|
val word = s.substring(i + 1, bar)
|
|
val num = s.substring(bar + 1, close)
|
|
out.add(Seg(word, jesus, italic, num))
|
|
i = close
|
|
} else buf.append(ch)
|
|
}
|
|
else -> buf.append(ch)
|
|
}
|
|
i++
|
|
}
|
|
flush()
|
|
return out
|
|
}
|
|
|
|
fun plain(s: String): String {
|
|
if (s.none { it == '{' || it == '[' || it == '<' }) return s
|
|
val sb = StringBuilder(s.length)
|
|
var i = 0
|
|
while (i < s.length) {
|
|
val ch = s[i]
|
|
when (ch) {
|
|
'<', '>', '[', ']' -> {}
|
|
'{' -> {
|
|
val bar = s.indexOf('|', i)
|
|
val close = s.indexOf('}', i)
|
|
if (bar in (i + 1) until close) {
|
|
sb.append(s, i + 1, bar); i = close
|
|
} else sb.append(ch)
|
|
}
|
|
else -> sb.append(ch)
|
|
}
|
|
i++
|
|
}
|
|
return sb.toString()
|
|
}
|
|
|
|
/** Strong's-tagged words in a verse, in order, deduplicated by number+word. */
|
|
fun words(s: String): List<Pair<String, String>> =
|
|
parse(s).filter { it.strong != null }.map { it.text to it.strong!! }.distinct()
|
|
}
|