diff options
Diffstat (limited to 'mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt')
-rw-r--r-- | mod/src/main/kotlin/moe/nea/ledger/NumberUtil.kt | 117 |
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 +} |