ess
March 17, 2026, 11:52pm
1
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 }}
ess
March 17, 2026, 11:59pm
3
Ha! That is sneaky - I can make this work (if it doesn’t). Thank you for the supersonic response time - wow
I have successfully implemented the inverse (roman2int), but was stuck with this for a while.
Cheers!
irkode
March 18, 2026, 7:59am
4
just to be on the cutting edge
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