Skip to content

Instantly share code, notes, and snippets.

@ymnk
Created February 12, 2009 07:55
Show Gist options
  • Save ymnk/62538 to your computer and use it in GitHub Desktop.
Save ymnk/62538 to your computer and use it in GitHub Desktop.
object RomanNumerals{
class RomanNumeralsException extends Exception
private val rn="IVXLCDM ".toList
def apply(n:Int):String={
type LS = List[String]
def n2ivx(n:Int, i:String, v:String, x:String):String = n match{
case 4 => i+v
case 9 => i+x
case _ => if(n >= 5) v+(i*(n-5)) else (i*n)
}
def loop(n:Int, rn:LS, result:LS):LS = n match{
case 0 => result
case _ =>
val i::v::(rest@(x::_)) = rn
loop(n/10, rest, n2ivx(n%10, i, v, x)::result)
}
if(0<n && n<=3999) loop(n, rn.map(_.toString), Nil).mkString("")
else throw new RomanNumeralsException
}
def apply(n:String):Int = {
type LC = List[Char]
def iv2n(n:LC, I:Char, V:Char, X:Char, r:Int):(LC, Int) = n match{
case V::I::n => (n, 4)
case V::_ => (n.tail, r+5)
case X::I::n => (n, 9)
case I::_ => iv2n(n.tail, I, V, X, r+1)
case _ => (n, r)
}
def loop(n:LC, rn:LC, digit:Int, result:Int):Int = n match {
case Nil => result
case _ =>
val i::v::(rest@(x::_)) = rn
val (n1, n2) = n match {
case (_@(`i`|`v`|`x`))::_ => iv2n(n, i, v, x, 0)
case n::_ if(!rest.exists(n==_)) => throw new RomanNumeralsException
case _ => (n, 0)
}
loop(n1, rest, digit*10, result+n2*digit)
}
loop(n.toList.reverse, rn, 1, 0)
}
def unapply(n:Int):Option[String] =
try{ Some(RomanNumerals.apply(n)) }catch{ case e => None }
def unapply(n:String):Option[Int] =
try{ Some(RomanNumerals.apply(n)) }catch{ case e => None }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment