import java.nio.charset.StandardCharsets
object Base36Codec {
/**
* Encodes a plain text string into a Base-36 representation.
* * Algorithm:
* 1. Convert the string's underlying bytes into an arbitrary-precision BigInt.
* 2. Leverage BigInt's built-in radix conversion `.toString(36)` to map to Base-36 digits.
*/
def encodeToBase36(text: String): String = {
if (text.isEmpty) return ""
// Convert string to bytes (UTF-8 guarantees cross-platform safety)
val bytes = text.getBytes(StandardCharsets.UTF_8)
// Treat the byte array as a positive magnitude BigInt (using signum = 1)
val bigInt = BigInt(1, bytes)
// Scala's BigInt provides built-in radix formatting up to base 36
bigInt.toString(36).toUpperCase
}
/**
* Decodes a Base-36 string back into its original text.
* * Algorithm:
* 1. Initialize a BigInt with the base-36 string representation.
* 2. Extract the underlying byte array and drop any leading zero bytes padding added by the sign bit.
*/
def decodeFromBase36(encoded: String): String = {
if (encoded.isEmpty) return ""
// Parse the base-36 string back into a BigInt using the standard radix parameter
val bigInt = BigInt(encoded.toLowerCase, 36)
// toByteArray returns a signed big-endian complement array.
val rawBytes = bigInt.toByteArray
// If the leading byte is 0, it was an artificial sign padding added by BigInteger.
// We clean it up so the original raw string bytes remain unaltered.
val cleanBytes = if (rawBytes.headOption.contains(0) && rawBytes.length > 1) {
rawBytes.tail
} else {
rawBytes
}
new String(cleanBytes, StandardCharsets.UTF_8)
}
def main(args: Array[String]): Unit = {
val text = "Hello Universe!"
val encoded = encodeToBase36(text)
val decoded = decodeFromBase36(encoded)
println(s"Original: $text")
println(s"Base-36 encoded: $encoded")
println(s"Decoded: $decoded")
}
}
/*
run:
Original: Hello Universe!
Base-36 encoded: LP4N024HJ1YVBVD84Y8TYQP
Decoded: Hello Universe!
*/