aboutsummaryrefslogtreecommitdiff
path: root/mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt
diff options
context:
space:
mode:
Diffstat (limited to 'mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt')
-rw-r--r--mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt117
1 files changed, 117 insertions, 0 deletions
diff --git a/mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt b/mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt
new file mode 100644
index 0000000..438f342
--- /dev/null
+++ b/mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt
@@ -0,0 +1,117 @@
+package moe.nea.ledger
+
+import net.minecraft.event.ClickEvent
+import net.minecraft.event.HoverEvent
+import net.minecraft.util.ChatComponentText
+import net.minecraft.util.ChatStyle
+import net.minecraft.util.EnumChatFormatting
+import net.minecraft.util.IChatComponent
+import java.time.Instant
+import java.time.LocalDateTime
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+import java.time.format.DateTimeFormatterBuilder
+import java.time.temporal.ChronoField
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+// language=regexp
+val SHORT_NUMBER_PATTERN = "[0-9]+(?:,[0-9]+)*(?:\\.[0-9]+)?[kKmMbB]?"
+
+// language=regexp
+val ROMAN_NUMBER_PATTERN = "[IVXLCDM]+"
+
+val romanNumbers = mapOf(
+ 'I' to 1,
+ 'V' to 5,
+ 'X' to 10,
+ 'L' to 50,
+ 'C' to 100,
+ 'D' to 500,
+ 'M' to 1000
+)
+
+fun parseRomanNumber(string: String): Int {
+ var smallestSeenSoFar = Int.MAX_VALUE
+ var lastSeenOfSmallest = 0
+ var amount = 0
+ for (c in string) {
+ val cV = romanNumbers[c]!!
+ if (cV == smallestSeenSoFar) {
+ lastSeenOfSmallest++
+ amount += cV
+ } else if (cV < smallestSeenSoFar) {
+ smallestSeenSoFar = cV
+ amount += cV
+ lastSeenOfSmallest = 1
+ } else {
+ amount -= lastSeenOfSmallest * smallestSeenSoFar * 2
+ smallestSeenSoFar = cV
+ amount += cV
+ lastSeenOfSmallest = 1
+ }
+ }
+ return amount
+}
+
+val siScalars = mapOf(
+ 'k' to 1_000.0,
+ 'K' to 1_000.0,
+ 'm' to 1_000_000.0,
+ 'M' to 1_000_000.0,
+ 'b' to 1_000_000_000.0,
+ 'B' to 1_000_000_000.0,
+)
+
+fun parseShortNumber(string: String): Double {
+ var k = string.replace(",", "")
+ val scalar = k.last()
+ var scalarMultiplier = siScalars[scalar]
+ if (scalarMultiplier == null) {
+ scalarMultiplier = 1.0
+ } else {
+ k = k.dropLast(1)
+ }
+ return k.toDouble() * scalarMultiplier
+}
+
+fun Pattern.matches(string: String): Boolean = matcher(string).matches()
+inline fun <T> Pattern.useMatcher(string: String, block: Matcher.() -> T): T? =
+ matcher(string).takeIf { it.matches() }?.let(block)
+
+fun <T> String.ifDropLast(suffix: String, block: (String) -> T): T? {
+ if (endsWith(suffix)) {
+ return block(dropLast(suffix.length))
+ }
+ return null
+}
+
+fun String.unformattedString(): String = replace("ยง.".toRegex(), "")
+
+val timeFormat: DateTimeFormatter = DateTimeFormatterBuilder()
+ .appendValue(ChronoField.DAY_OF_MONTH, 2)
+ .appendLiteral(".")
+ .appendValue(ChronoField.MONTH_OF_YEAR, 2)
+ .appendLiteral(".")
+ .appendValue(ChronoField.YEAR, 4)
+ .appendLiteral(" ")
+ .appendValue(ChronoField.HOUR_OF_DAY, 2)
+ .appendLiteral(":")
+ .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+ .appendLiteral(":")
+ .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+ .toFormatter()
+
+fun Instant.formatChat(): IChatComponent {
+ val text = ChatComponentText(
+ LocalDateTime.ofInstant(this, ZoneId.systemDefault()).format(timeFormat)
+ )
+ text.setChatStyle(
+ ChatStyle()
+ .setChatClickEvent(
+ ClickEvent(ClickEvent.Action.OPEN_URL, "https://time.is/${this.epochSecond}"))
+ .setChatHoverEvent(
+ HoverEvent(HoverEvent.Action.SHOW_TEXT, ChatComponentText("Click to show on time.is")))
+ .setColor(EnumChatFormatting.AQUA))
+ return text
+}