/src/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs

https://github.com/EPPlusSoftware/EPPlus · C# · 95 lines · 80 code · 3 blank · 12 comment · 12 complexity · 55366eecf014edda79b8b85eb2017ee3 MD5 · raw file

  1. /*************************************************************************************************
  2. Required Notice: Copyright (C) EPPlus Software AB.
  3. This software is licensed under PolyForm Noncommercial License 1.0.0
  4. and may only be used for noncommercial purposes
  5. https://polyformproject.org/licenses/noncommercial/1.0.0/
  6. A commercial license to use this software can be purchased at https://epplussoftware.com
  7. *************************************************************************************************
  8. Date Author Change
  9. *************************************************************************************************
  10. 01/27/2020 EPPlus Software AB Initial release EPPlus 5
  11. *************************************************************************************************/
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Globalization;
  15. using System.Linq;
  16. using System.Text;
  17. using System.Text.RegularExpressions;
  18. using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
  19. using OfficeOpenXml.FormulaParsing.Excel.Functions.Metadata;
  20. using OfficeOpenXml.FormulaParsing.ExpressionGraph;
  21. namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text
  22. {
  23. [FunctionMetadata(
  24. Category = ExcelFunctionCategory.Text,
  25. EPPlusVersion = "4",
  26. Description = "Converts a text string into a numeric value")]
  27. internal class Value : ExcelFunction
  28. {
  29. public Value(CultureInfo ci)
  30. {
  31. _cultureInfo = ci;
  32. _groupSeparator = _cultureInfo.NumberFormat.NumberGroupSeparator;
  33. _decimalSeparator = _cultureInfo.NumberFormat.NumberDecimalSeparator;
  34. _timeSeparator = _cultureInfo.DateTimeFormat.TimeSeparator;
  35. _shortTimePattern = _cultureInfo.DateTimeFormat.ShortTimePattern;
  36. }
  37. private readonly CultureInfo _cultureInfo;
  38. private readonly string _groupSeparator;
  39. private readonly string _decimalSeparator;
  40. private readonly string _timeSeparator;
  41. private readonly string _shortTimePattern;
  42. private readonly DateValue _dateValueFunc = new DateValue();
  43. private readonly TimeValue _timeValueFunc = new TimeValue();
  44. public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context)
  45. {
  46. ValidateArguments(arguments, 1);
  47. var val = ArgToString(arguments, 0);
  48. double result = 0d;
  49. if (string.IsNullOrEmpty(val)) return CreateResult(result, DataType.Integer);
  50. val = val.TrimEnd(' ');
  51. bool isPercentage = false;
  52. if(val.EndsWith("%"))
  53. {
  54. val = val.TrimEnd('%');
  55. isPercentage = true;
  56. }
  57. if(val.StartsWith("(") && val.EndsWith(")"))
  58. {
  59. var numCandidate = val.Substring(1, val.Length - 2);
  60. if(double.TryParse(numCandidate, NumberStyles.Any, _cultureInfo, out double tmp))
  61. {
  62. val = "-" + numCandidate;
  63. }
  64. }
  65. if (Regex.IsMatch(val, $"^[\\d]*({Regex.Escape(_groupSeparator)}?[\\d]*)?({Regex.Escape(_decimalSeparator)}[\\d]*)*?[ ?% ?]?$", RegexOptions.Compiled))
  66. {
  67. result = double.Parse(val, _cultureInfo);
  68. return CreateResult(isPercentage ? result/100 : result, DataType.Decimal);
  69. }
  70. if (double.TryParse(val, NumberStyles.Float, _cultureInfo, out result))
  71. {
  72. return CreateResult(isPercentage ? result/100d : result, DataType.Decimal);
  73. }
  74. var timeSeparator = Regex.Escape(_timeSeparator);
  75. if (Regex.IsMatch(val, @"^[\d]{1,2}" + timeSeparator + @"[\d]{2}(" + timeSeparator + @"[\d]{2})?$", RegexOptions.Compiled))
  76. {
  77. var timeResult = _timeValueFunc.Execute(val);
  78. if (timeResult.DataType == DataType.Date)
  79. {
  80. return timeResult;
  81. }
  82. }
  83. var dateResult = _dateValueFunc.Execute(val);
  84. if (dateResult.DataType == DataType.Date)
  85. {
  86. return dateResult;
  87. }
  88. return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError);
  89. }
  90. }
  91. }