diff --git a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs index eac01ce..72401fd 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs @@ -19,6 +19,7 @@ ce.RegisterFunction("ACOSH", 1, Acosh); ce.RegisterFunction("ACOT", 1, Acot); ce.RegisterFunction("ACOTH", 1, Acoth); + ce.RegisterFunction("ARABIC", 1, Arabic); ce.RegisterFunction("ASIN", 1, Asin); ce.RegisterFunction("ASINH", 1, Asinh); ce.RegisterFunction("ATAN", 1, Atan); @@ -516,6 +517,31 @@ return 0.5 * Math.Log((number + 1) / (number - 1)); } + private static object Arabic(List p) + { + string input = ((string)p[0]).Trim(); + + try + { + if (input == "") + return 0; + if (input == "-") + throw new NumberException(); + else if (input[0] == '-') + return -XLMath.RomanToArabic(input.Substring(1)); + else + return XLMath.RomanToArabic(input); + } + catch (ArgumentOutOfRangeException) + { + throw new CellValueException(); + } + catch + { + throw; + } + } + private static object Asinh(List p) { return XLMath.ASinh(p[0]); diff --git a/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs b/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs index 693f68f..85f5fe2 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs @@ -118,5 +118,38 @@ throw new ArgumentOutOfRangeException("something bad happened"); } + public static int RomanToArabic(string text) + { + if (text == "") + return 0; + if (text.StartsWith("M", StringComparison.InvariantCultureIgnoreCase)) + return 1000 + RomanToArabic(text.Substring(1)); + if (text.StartsWith("CM", StringComparison.InvariantCultureIgnoreCase)) + return 900 + RomanToArabic(text.Substring(2)); + if (text.StartsWith("D", StringComparison.InvariantCultureIgnoreCase)) + return 500 + RomanToArabic(text.Substring(1)); + if (text.StartsWith("CD", StringComparison.InvariantCultureIgnoreCase)) + return 400 + RomanToArabic(text.Substring(2)); + if (text.StartsWith("C", StringComparison.InvariantCultureIgnoreCase)) + return 100 + RomanToArabic(text.Substring(1)); + if (text.StartsWith("XC", StringComparison.InvariantCultureIgnoreCase)) + return 90 + RomanToArabic(text.Substring(2)); + if (text.StartsWith("L", StringComparison.InvariantCultureIgnoreCase)) + return 50 + RomanToArabic(text.Substring(1)); + if (text.StartsWith("XL", StringComparison.InvariantCultureIgnoreCase)) + return 40 + RomanToArabic(text.Substring(2)); + if (text.StartsWith("X", StringComparison.InvariantCultureIgnoreCase)) + return 10 + RomanToArabic(text.Substring(1)); + if (text.StartsWith("IX", StringComparison.InvariantCultureIgnoreCase)) + return 9 + RomanToArabic(text.Substring(2)); + if (text.StartsWith("V", StringComparison.InvariantCultureIgnoreCase)) + return 5 + RomanToArabic(text.Substring(1)); + if (text.StartsWith("IV", StringComparison.InvariantCultureIgnoreCase)) + return 4 + RomanToArabic(text.Substring(2)); + if (text.StartsWith("I", StringComparison.InvariantCultureIgnoreCase)) + return 1 + RomanToArabic(text.Substring(1)); + + throw new ArgumentOutOfRangeException("text is not a valid roman number"); + } } } diff --git a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs index 1152e62..0165213 100644 --- a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs +++ b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs @@ -148,6 +148,31 @@ Assert.Throws(() => XLWorkbook.EvaluateExpr(string.Format(@"ACOTH({0})", input.ToString(CultureInfo.InvariantCulture)))); } + [TestCase("LVII", 57)] + [TestCase("mcmxii", 1912)] + [TestCase("", 0)] + [TestCase("-IV", -4)] + [TestCase(" XIV", 14)] + [TestCase("MCMLXXXIII ", 1983)] + public void Arabic_ReturnsCorrectNumber(string roman, int arabic) + { + var actual = (int)XLWorkbook.EvaluateExpr(string.Format($"ARABIC(\"{roman}\")")); + Assert.AreEqual(arabic, actual); + } + + [Test] + public void Arabic_ThrowsNumberExceptionOnMinus() + { + Assert.Throws(() => XLWorkbook.EvaluateExpr("ARABIC(\"-\")")); + } + + [TestCase("- I")] + [TestCase("roman")] + public void Arabic_ThrowsValueExceptionOnInvalidNumber(string invalidRoman) + { + Assert.Throws(() => XLWorkbook.EvaluateExpr($"ARABIC(\"{invalidRoman}\")")); + } + [TestCase(4, 3, 20)] [TestCase(10, 3, 220)] [TestCase(0, 0, 1)]