正規表現と数学パーサー

むかしむかし、C#の数式のパーサーが必要でした。 もちろん、完成した実装をダウンロードすることは問題ではありません。 しかし、その年にのみ、私はインターネットを持っていませんでした。 その結果、完全にためらいもなく、パーサー、ステートマシン、その他の理論的基礎もなしに、正規表現で記述されました。 10分。算術演算と括弧のみが必要だったことは注目に値します。 三角関数などのサポートは不要でした。



まず、数値とアクションの正規表現を強調します。

private const string RegexBr = "\\(([1234567890\\.\\+\\-\\*\\/^%]*)\\)"; //  private const string RegexNum = "[-]?\\d+\\.?\\d*"; //  private const string RegexMulOp = "[\\*\\/^%]"; //   private const string RegexAddOp = "[\\+\\-]"; //  
      
      





次に、結果の文字列を要素に分割し、それらを再帰的に計算するメソッド:

 public static double Parse(string str) { //   var matchSk = Regex.Match(str, RegexBr); if (matchSk.Groups.Count > 1) { string inner = matchSk.Groups[0].Value.Substring(1, matchSk.Groups[0].Value.Trim().Length - 2); string left = str.Substring(0, matchSk.Index); string right = str.Substring(matchSk.Index + matchSk.Length); return Parse(left + Parse(inner).ToString(CultureInfo.InvariantCulture) + right); } //   var matchMulOp = Regex.Match(str, string.Format("({0})\\s?({1})\\s?({2})\\s?", RegexNum, RegexMulOp, RegexNum)); var matchAddOp = Regex.Match(str, string.Format("({0})\\s?({1})\\s?({2})\\s?", RegexNum, RegexAddOp, RegexNum)); var match = matchMulOp.Groups.Count > 1 ? matchMulOp : matchAddOp.Groups.Count > 1 ? matchAddOp : null; if (match != null) { string left = str.Substring(0, match.Index); string right = str.Substring(match.Index + match.Length); return Parse(left + ParseAct(match).ToString(CultureInfo.InvariantCulture) + right); } //   try { return double.Parse(str, CultureInfo.InvariantCulture); } catch (FormatException) { throw new FormatException(string.Format("   '{0}'", str)); } }
      
      





最後に、アクションの値を直接計算するメソッドを作成します。

 private static double ParseAct(Match match) { double a = double.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); double b = double.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture); switch (match.Groups[2].Value) { case "+": return a + b; case "-": return a - b; case "*": return a * b; case "/": return a / b; case "^": return Math.Pow(a, b); case "%": return a % b; default: throw new FormatException($"   '{match.Value}'"); } }
      
      





そのような「異常なプログラミング」がありました。 私はソースコードに完全に何も見当たりません-誰もそれをほとんど必要としません。 ただし、いずれにしても、3つのクラスを作成するのは数秒で完了します。



ご清聴ありがとうございました。



All Articles