mirror of
https://github.com/rwinkhart/convertroman.git
synced 2026-09-03 15:47:16 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9812cc6abd | ||
|
|
65e09936c0 | ||
|
|
6148897d85 | ||
|
|
3e38327aa4 | ||
|
|
ba1c6d30ed | ||
|
|
fc6dbc7d0d | ||
|
|
63f3025096 | ||
|
|
afad2b7ee8 | ||
|
|
9431220427 |
@@ -2,20 +2,27 @@
|
||||
|
||||
This package was adapted from [romannumeral](https://github.com/brandenc40/romannumeral) to fit my specific minimal use-case.
|
||||
|
||||
All functionality except for the ability to convert integers to **lowercase** roman numerals has been removed.
|
||||
All functionality except for the ability to convert integers to roman numerals has been removed.
|
||||
|
||||
Since I have less functionality to worry about, I was also able to implement vinculum notation support to extend the range of supported integers to 3,999,999.
|
||||
I also added the ability to choose between uppercase and lowercase roman numerals (optimized for lowercase due to my personal use-case).
|
||||
|
||||
If you need any additional functionality or further documentation, please see the original package.
|
||||
|
||||
### Benchmark Results
|
||||
|
||||
Note that the benchmark results of this fork are slower than upstream due to the added vinculum notation support.
|
||||
This benchmark tests the highest supported integer (3,999,999) while upstream tests with 3,999.
|
||||
|
||||
```sh
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/rwinkhart/convertroman
|
||||
cpu: AMD Ryzen 9 3900X 12-Core Processor
|
||||
BenchmarkFromInt-24 61993154 20.82 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkFromInt-24 5372720 237.0 ns/op 24 B/op 1 allocs/op
|
||||
BenchmarkFromIntCapital-24 2117424 570.9 ns/op 64 B/op 3 allocs/op
|
||||
PASS
|
||||
ok github.com/rwinkhart/convertroman 1.827s
|
||||
ok github.com/rwinkhart/convertroman 4.098s
|
||||
```
|
||||
|
||||
### Example
|
||||
@@ -28,11 +35,22 @@ import (
|
||||
rom "github.com/rwinkhart/convertroman"
|
||||
)
|
||||
|
||||
func ExampleFromInt() {
|
||||
roman := FromInt(4)
|
||||
func main() {
|
||||
var roman string
|
||||
|
||||
// lowercase
|
||||
roman = rom.FromInt(4)
|
||||
if roman == "OOB" {
|
||||
panic("Input integer is out of bounds")
|
||||
panic("Input integer is out of bounds (greater than 3,999,999)")
|
||||
}
|
||||
fmt.Println(roman == "IV") // True
|
||||
fmt.Println(roman == "iv") // True
|
||||
|
||||
// capital (slightly slower)
|
||||
// this example uses a number in vinculum notation to show that ANSI escape codes are used to provide the overline
|
||||
roman = rom.FromIntCapital(4)
|
||||
if roman == "OOB" {
|
||||
panic("Input integer is out of bounds (greater than 3,999,999)")
|
||||
}
|
||||
fmt.Println(roman == "\033[53mIV\033[0mLXV") // True
|
||||
}
|
||||
```
|
||||
|
||||
+40
-7
@@ -1,8 +1,6 @@
|
||||
package convertroman
|
||||
|
||||
// Currently only supports Roman Numerals without viniculum (1-3999; "OOB" is returned for values outside this range)
|
||||
// See here for details on viniculum:
|
||||
// https://en.wikipedia.org/wiki/Roman_numerals#Large_numbers
|
||||
import "strings"
|
||||
|
||||
var (
|
||||
// lookup arrays used for converting from an int to a roman numeral extremely quickly.
|
||||
@@ -14,13 +12,48 @@ var (
|
||||
)
|
||||
|
||||
// FromInt converts an integer value to a roman numeral string.
|
||||
// "OOB" is returned if the integer is not between 1 and 3999.
|
||||
// The function will return "0" if the input integer is less than 1.
|
||||
// The function will return "OOB" if the input integer is greater than
|
||||
// or equal to 4,000,000 (the roman numeral vinculum limit).
|
||||
func FromInt(input int) string {
|
||||
// ensure provided integer is within the valid range
|
||||
if input < 1 || input > 3999 {
|
||||
if input < 1 {
|
||||
return "0"
|
||||
} else if input < 4000 {
|
||||
return baseRange(input)
|
||||
} else if input < 4000000 {
|
||||
thousands, remainder := separateThousands(input)
|
||||
return vinculumRange(thousands) + baseRange(remainder)
|
||||
} else {
|
||||
return "OOB"
|
||||
}
|
||||
}
|
||||
|
||||
// convert the integer to a roman numeral string and return it
|
||||
// FromIntCapital very inefficiently converts an integer value to a CAPITAL roman numeral string.
|
||||
// Note that this package is optimized for lowercase roman numerals. As such, this function is a slow afterthought.
|
||||
func FromIntCapital(input int) string {
|
||||
if input < 4000 {
|
||||
// if below vinculum range, return the translated result
|
||||
return strings.ToUpper(FromInt(input))
|
||||
} else {
|
||||
// if in vinculum range, remove the ANSI escape codes, capitalize the result, and reapply the ANSI escape codes
|
||||
noPrefix := strings.TrimPrefix(FromInt(input), "\033[53m")
|
||||
secondIndex := strings.Index(noPrefix, "\033[0m")
|
||||
capitalPreANSI := strings.ToUpper(noPrefix[:secondIndex] + noPrefix[secondIndex+4:])
|
||||
return "\033[53m" + capitalPreANSI[:secondIndex] + "\033[0m" + capitalPreANSI[secondIndex:]
|
||||
}
|
||||
}
|
||||
|
||||
// separateThousands separates an integer into two parts: the thousands and the remainder.
|
||||
func separateThousands(num int) (int, int) {
|
||||
return num / 1000, num % 1000
|
||||
}
|
||||
|
||||
// vinculumRange returns a roman numeral string for an integer greater than 3999.
|
||||
func vinculumRange(input int) string {
|
||||
return "\033[53m" + baseRange(input) + "\033[0m"
|
||||
}
|
||||
|
||||
// baseRange returns a roman numeral string for an integer between 1 and 3999.
|
||||
func baseRange(input int) string {
|
||||
return r3[input%1e4/1e3] + r2[input%1e3/1e2] + r1[input%100/10] + r0[input%10]
|
||||
}
|
||||
|
||||
+25
-11
@@ -1,7 +1,6 @@
|
||||
package convertroman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -22,6 +21,22 @@ var testCases = map[string]int{
|
||||
"dcccxlix": 849, "cmiv": 904, "m": 1000, "mvii": 1007, "mlxvi": 1066,
|
||||
"mccxxxiv": 1234, "mdcclxxvi": 1776, "mmxxi": 2021, "mmdcccvi": 2806,
|
||||
"mmcmxcix": 2999, "mmm": 3000, "mmmcmlxxix": 3979, "mmmcmxcix": 3999,
|
||||
"\033[53miv\033[0m": 4000, "\033[53mv\033[0m": 5000, "\033[53mvi\033[0m": 6000,
|
||||
"\033[53mvii\033[0m": 7000, "\033[53mviii\033[0m": 8000, "\033[53mix\033[0m": 9000, "\033[53mx\033[0m": 10000, "\033[53mxi\033[0m": 11000, "\033[53mxii\033[0m": 12000,
|
||||
"\033[53mxiii\033[0m": 13000, "\033[53mxiv\033[0m": 14000, "\033[53mxv\033[0mxcix": 15099, "\033[53mxvi\033[0m": 16000, "\033[53mxvii\033[0m": 17000,
|
||||
"\033[53mxviii\033[0mi": 18001, "\033[53mxix\033[0m": 19000, "\033[53mxx\033[0m": 20000, "\033[53mxxxi\033[0m": 31000, "\033[53mxxxii\033[0m": 32000,
|
||||
"\033[53mxxxiii\033[0m": 33000, "\033[53mxxxiv\033[0m": 34000, "\033[53mxxxv\033[0m": 35000, "\033[53mxxxvi\033[0m": 36000, "\033[53mxxxvii\033[0m": 37000,
|
||||
"\033[53mxxxviii\033[0m": 38000, "\033[53mxxxix\033[0m": 39000, "\033[53mxl\033[0m": 40000, "\033[53mxli\033[0m": 41000, "\033[53mxlii\033[0m": 42000,
|
||||
"\033[53mxliii\033[0m": 43000, "\033[53mxliv\033[0m": 44000, "\033[53mxlv\033[0mlvi": 45056, "\033[53mxlvi\033[0m": 46000, "\033[53mxlvii\033[0m": 47000,
|
||||
"\033[53mxlviii\033[0m": 48000, "\033[53mxlix\033[0m": 49000, "\033[53ml\033[0m": 50000, "\033[53mlxxxix\033[0mc": 89100, "\033[53mxc\033[0m": 90000,
|
||||
"\033[53mxci\033[0m": 91000, "\033[53mxcii\033[0m": 92000, "\033[53mxciii\033[0m": 93000, "\033[53mxciv\033[0m": 94000, "\033[53mxcv\033[0m": 95000,
|
||||
"\033[53mxcvi\033[0m": 96000, "\033[53mxcvii\033[0m": 97000, "\033[53mxcviii\033[0m": 98000, "\033[53mxcix\033[0m": 99000, "\033[53mc\033[0m": 100000,
|
||||
"\033[53mci\033[0m": 101000, "\033[53mcii\033[0mcxxvii": 102127, "\033[53mciii\033[0m": 103000, "\033[53mciv\033[0m": 104000, "\033[53mcv\033[0m": 105000,
|
||||
"\033[53mcvi\033[0m": 106000, "\033[53mcvii\033[0m": 107000, "\033[53mcviii\033[0m": 108000, "\033[53mcix\033[0m": 109000, "\033[53mcxlix\033[0m": 149000,
|
||||
"\033[53mcccxlix\033[0m": 349000, "\033[53mcdlvi\033[0m": 456000, "\033[53md\033[0m": 500000, "\033[53mdciv\033[0m": 604000, "\033[53mdcclxxxix\033[0m": 789000,
|
||||
"\033[53mdcccxlix\033[0m": 849000, "\033[53mcmiv\033[0m": 904000, "\033[53mm\033[0m": 1000000, "\033[53mmvii\033[0m": 1007000, "\033[53mmlxvi\033[0m": 1066000,
|
||||
"\033[53mmccxxxiv\033[0m": 1234000, "\033[53mmdcclxxvi\033[0m": 1776000, "\033[53mmmxxi\033[0m": 2021000, "\033[53mmmdcccvi\033[0mcdxlii": 2806442,
|
||||
"\033[53mmmcmxcix\033[0m": 2999000, "\033[53mmmm\033[0m": 3000000, "\033[53mmmmcmlxxix\033[0m": 3979000, "\033[53mmmmcmxcix\033[0m": 3999000,
|
||||
}
|
||||
|
||||
func TestFromInt(t *testing.T) {
|
||||
@@ -33,27 +48,26 @@ func TestFromInt(t *testing.T) {
|
||||
t.Errorf("FromInt(%d) = %s; want %s", input, out, expected)
|
||||
}
|
||||
}
|
||||
out := FromInt(100000)
|
||||
out := FromInt(4000000)
|
||||
if out != "OOB" {
|
||||
t.Errorf("FromInt(%d) expected an error", 100000)
|
||||
t.Errorf("FromInt(%d) expected an error", 4000000)
|
||||
}
|
||||
out = FromInt(0)
|
||||
if out != "OOB" {
|
||||
t.Errorf("FromInt(%d) expected an error", 0)
|
||||
if out != "0" {
|
||||
t.Errorf("FromInt(%d) something went wrong (0 should resolve to 0)", 0)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFromInt(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = FromInt(3999)
|
||||
_ = FromInt(3999999)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleFromInt() {
|
||||
roman := FromInt(4)
|
||||
if roman == "OOB" {
|
||||
panic("Input integer is out of bounds")
|
||||
func BenchmarkFromIntCapital(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = FromIntCapital(3999999)
|
||||
}
|
||||
fmt.Println(roman == "IV") // True
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user