Convert Roman Numerals to Int

Hello!

I am attempting to implement a template partial that will convert an int into its equivalent in roman numerals.

I would like to implement something like the toRoman function found here: roman-number-go/roman.go at master · chonla/roman-number-go · GitHub

The trouble is with the for loop that operates like a while. Hugo doesn’t (seem to) have the ability to execute this type of loop.

I’m becoming fairly comfortable with writing complex templates, but I can’t seem to think of a way to do this without that type of loop.

Untested, something like this in a partial should work:

{{/* Usage: {{ partial "romanToInt.html" "XIV" }} -> 14 */}}
{{ $roman := . | upper }}
{{ $total := 0 }}

{{/* Replace subtractive cases */}}
{{ $roman = replace $roman "IV" "IIII" }}
{{ $roman = replace $roman "IX" "VIIII" }}
{{ $roman = replace $roman "XL" "XXXX" }}
{{ $roman = replace $roman "XC" "LXXXX" }}
{{ $roman = replace $roman "CD" "CCCC" }}
{{ $roman = replace $roman "CM" "DCCCC" }}

{{/* Define values */}}
{{ $map := dict "I" 1 "V" 5 "X" 10 "L" 50 "C" 100 "D" 500 "M" 1000 }}

{{/* Calculate */}}
{{ range split $roman "" }}
    {{ $total = add $total (index $map .) }}
{{ end }}

{{ return $total }}

Ha! That is sneaky - I can make this work (if it doesn’t). Thank you for the supersonic response time - wow :slight_smile:

I have successfully implemented the inverse (roman2int), but was stuck with this for a while.

Cheers!

just to be on the cutting edge :wink:

with hugo v0.158.0 you could use strings.ReplacePairs

the {{/* Replace subtractive cases */}} will be:

{{ $roman = $roman | strings.ReplacePairs "IV" "IIII" "IX" "VIIII" "XL" "XXXX" "XC" "LXXXX" "CD" "CCCC" "CM" "DCCCC" }}

The speed improvement is academic in that case

INFO  timer:  name 3_ReplacePairs count 100000 duration 396.4264ms average 3.964µs median 0s
INFO  timer:  name 1_romanReplace count 100000 duration 654.8087ms average 6.548µs median 0s```

to save another academic second on 100000 iterations you could replace the loop with this unreadable functional approach:

{{ $total = int (math.Sum (apply (split $roman "") "index" $map ".")) }}

INFO  timer:  name 4_Apply count 100000 duration 1.4727021s average 14.727µs median 0s
INFO  timer:  name 2_Loop count 100000 duration 2.1269056s average 21.269µs median 0