# encoding: ascii
# api: powershell
# title: ConvertFrom-RomanNumeral
# description: I have encountered “real world” uses for functions like this. As an exercise I
# version: 3.0
# type: function
# author: Vince Ypma
# license: CC0
# function: ConvertFrom-RomanNumeral
# x-poshcode-id: 5659
# x-archived: 2016-05-19T06:30:09
# x-published: 2016-01-03T01:10:00
#
# translated an old FORTH word (function) to a PowerShell function. Then (as an
# exercise) promoted it to an Advanced Function. It requires PowerShell version
# 3.0 because it uses an [ordered] hashtable.
#
function ConvertFrom-RomanNumeral
{
<#
.SYNOPSIS
Converts a roman numeral to a number.
.DESCRIPTION
Converts a roman numeral - in the range of I..MMMCMXCIX - to a number.
.PARAMETER Numeral
A roman numeral in the range I..MMMCMXCIX (1..3,999).
.INPUTS
System.String
.OUTPUTS
System.Int32
.NOTES
Requires PowerShell version 3.0
.EXAMPLE
ConvertFrom-RomanNumeral -Numeral MMXIV
.EXAMPLE
"MMXIV" | ConvertFrom-RomanNumeral
#>
[CmdletBinding()]
[OutputType([int])]
Param
(
[Parameter(Mandatory=$true,
HelpMessage="Enter a roman numeral in the range I..MMMCMXCIX",
ValueFromPipeline=$true,
Position=0)]
[ValidatePattern("(?x)^
M{0,3} # Thousands
(CM|CD|D?C{0,3}) # Hundreds
(XC|XL|L?X{0,3}) # Tens
(IX|IV|V?I{0,3}) # Ones
$")]
[string]
$Numeral
)
Begin
{
# This must be an [ordered] hashtable
$RomanToDecimal = [ordered]@{
M = 1000
CM = 900
D = 500
CD = 400
C = 100
XC = 90
L = 50
X = 10
IX = 9
V = 5
IV = 4
I = 1
}
}
Process
{
$roman = $Numeral + '$'
$value = 0
do
{
foreach ($key in $RomanToDecimal.Keys)
{
if ($key.Length -eq 1)
{
if ($key -match $roman.Substring(0,1))
{
$value += $RomanToDecimal.$key
$roman = $roman.Substring(1)
break
}
}
else
{
if ($key -match $roman.Substring(0,2))
{
$value += $RomanToDecimal.$key
$roman = $roman.Substring(2)
break
}
}
}
}
until ($roman -eq '$')
$value
}
End
{
}
}