Question: Having a hard time getting a the normalizer through the constructor, any help would be a lifesaver, thanks. using System; using System.Collections.Generic; using System.Linq; using
Having a hard time getting a the normalizer through the constructor, any help would be a lifesaver, thanks.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions;
namespace SpreadsheetUtilities { /// /// Represents formulas written in standard infix notation using standard precedence /// rules. The allowed symbols are non-negative numbers written using double-precision /// floating-point syntax; variables that consist of a letter or underscore followed by /// zero or more letters, underscores, or digits; parentheses; and the four operator /// symbols +, -, *, and /. /// /// Spaces are significant only insofar that they delimit tokens. For example, "xy" is /// a single variable, "x y" consists of two variables "x" and y; "x23" is a single variable; /// and "x 23" consists of a variable "x" and a number "23". /// /// Associated with every formula are two delegates: a normalizer and a validator. The /// normalizer is used to convert variables into a canonical form, and the validator is used /// to add extra restrictions on the validity of a variable (beyond the standard requirement /// that it consist of a letter or underscore followed by zero or more letters, underscores, /// or digits.) Their use is described in detail in the constructor and method comments. /// public class Formula { /// /// Creates a Formula from a string that consists of an infix expression written as /// described in the class comment. If the expression is syntactically invalid, /// throws a FormulaFormatException with an explanatory Message. /// /// The associated normalizer is the identity function, and the associated validator /// maps every string to true. /// public Formula(String formula) : this(formula, s => s, s => true) { }
/// /// Creates a Formula from a string that consists of an infix expression written as /// described in the class comment. If the expression is syntactically incorrect, /// throws a FormulaFormatException with an explanatory Message. /// /// The associated normalizer and validator are the second and third parameters, /// respectively. /// /// If the formula contains a variable v such that normalize(v) is not a legal variable, /// throws a FormulaFormatException with an explanatory message. /// /// If the formula contains a variable v such that isValid(normalize(v)) is false, /// throws a FormulaFormatException with an explanatory message. /// /// Suppose that N is a method that converts all the letters in a string to upper case, and /// that V is a method that returns true only if a string consists of one letter followed /// by one digit. Then: /// /// new Formula("x2+y3", N, V) should succeed /// new Formula("x+y3", N, V) should throw an exception, since V(N("x")) is false /// new Formula("2x+y3", N, V) should throw an exception, since "2x+y3" is syntactically incorrect. /// public Formula(String formula, Func normalize, Func isValid) { }
/// /// Evaluates this Formula, using the lookup delegate to dete rmine the values of /// variables. When a variable symbol v needs to be determined, it should be looked up /// via lookup(normalize(v)). (Here, normalize is the normalizer that was passed to /// the constructor.) /// /// For example, if L("x") is 2, L("X") is 4, and N is a method that converts all the letters /// in a string to upper case: /// /// new Formula("x+7", N, s => true).Evaluate(L) is 11 /// new Formula("x+7").Evaluate(L) is 9 /// /// Given a variable symbol as its parameter, lookup returns the variable's value /// (if it has one) or throws an ArgumentException (otherwise). /// /// If no undefined variables or divisions by zero are encountered when evaluating /// this Formula, the value is returned. Otherwise, a FormulaError is returned. /// The Reason property of the FormulaError should have a meaningful explanation. /// /// This method should never throw an exception. /// public object Evaluate(Func lookup) { return null; }
/// /// Enumerates the normalized versions of all of the variables that occur in this /// formula. No normalization may appear more than once in the enumeration, even /// if it appears more than once in this Formula. /// /// For example, if N is a method that converts all the letters in a string to upper case: /// /// new Formula("x+y*z", N, s => true).GetVariables() should enumerate "X", "Y", and "Z" /// new Formula("x+X*z", N, s => true).GetVariables() should enumerate "X" and "Z". /// new Formula("x+X*z").GetVariables() should enumerate "x", "X", and "z". /// public IEnumerable GetVariables() { return null; }
/// /// Returns a string containing no spaces which, if passed to the Formula /// constructor, will produce a Formula f such that this.Equals(f). All of the /// variables in the string should be normalized. /// /// For example, if N is a method that converts all the letters in a string to upper case: /// /// new Formula("x + y", N, s => true).ToString() should return "X+Y" /// new Formula("x + Y").ToString() should return "x+Y" /// public override string ToString() { return null; }
/// /// If obj is null or obj is not a Formula, returns false. Otherwise, reports /// whether or not this Formula and obj are equal. /// /// Two Formulae are considered equal if they consist of the same tokens in the /// same order. To determine token equality, all tokens are compared as strings /// except for numeric tokens and variable tokens. /// Numeric tokens are considered equal if they are equal after being "normalized" /// by C#'s standard conversion from string to double, then back to string. This /// eliminates any inconsistencies due to limited floating point precision. /// Variable tokens are considered equal if their normalized forms are equal, as /// defined by the provided normalizer. /// /// For example, if N is a method that converts all the letters in a string to upper case: /// /// new Formula("x1+y2", N, s => true).Equals(new Formula("X1 + Y2")) is true /// new Formula("x1+y2").Equals(new Formula("X1+Y2")) is false /// new Formula("x1+y2").Equals(new Formula("y2+x1")) is false /// new Formula("2.0 + x7").Equals(new Formula("2.000 + x7")) is true /// public override bool Equals(object obj) { return false; }
/// /// Reports whether f1 == f2, using the notion of equality from the Equals method. /// Note that if both f1 and f2 are null, this method should return true. If one is /// null and one is not, this method should return false. /// public static bool operator ==(Formula f1, Formula f2) { return false; }
/// /// Reports whether f1 != f2, using the notion of equality from the Equals method. /// Note that if both f1 and f2 are null, this method should return false. If one is /// null and one is not, this method should return true. /// public static bool operator !=(Formula f1, Formula f2) { return false; }
/// /// Returns a hash code for this Formula. If f1.Equals(f2), then it must be the /// case that f1.GetHashCode() == f2.GetHashCode(). Ideally, the probability that two /// randomly-generated unequal Formulae have the same hash code should be extremely small. /// public override int GetHashCode() { ` return 0; }
/// /// Given an expression, enumerates the tokens that compose it. Tokens are left paren; /// right paren; one of the four operator symbols; a string consisting of a letter or underscore /// followed by zero or more letters, digits, or underscores; a double literal; and anything that doesn't /// match one of those patterns. There are no empty tokens, and no token contains white space. /// private static IEnumerable GetTokens(String formula) { // Patterns for individual tokens String lpPattern = @"\("; String rpPattern = @"\)"; String opPattern = @"[\+\-*/]"; String varPattern = @"[a-zA-Z_](?: [a-zA-Z_]|\d)*"; String doublePattern = @"(?: \d+\.\d* | \d*\.\d+ | \d+ ) (?: [eE][\+-]?\d+)?"; String spacePattern = @"\s+";
// Overall pattern String pattern = String.Format("({0}) | ({1}) | ({2}) | ({3}) | ({4}) | ({5})", lpPattern, rpPattern, opPattern, varPattern, doublePattern, spacePattern);
// Enumerate matching tokens that don't consist solely of white space. foreach (String s in Regex.Split(formula, pattern, RegexOptions.IgnorePatternWhitespace)) { if (!Regex.IsMatch(s, @"^\s*$", RegexOptions.Singleline)) { yield return s; } }
} }
/// /// Used to report syntactic errors in the argument to the Formula constructor. /// public class FormulaFormatException : Exception { /// /// Constructs a FormulaFormatException containing the explanatory message. /// public FormulaFormatException(String message) : base(message) { } }
/// /// Used as a possible return value of the Formula.Evaluate method. /// public struct FormulaError { /// /// Constructs a FormulaError containing the explanatory reason. /// /// public FormulaError(String reason) : this() { Reason = reason; }
/// /// The reason why this FormulaError was created. /// public string Reason { get; private set; } } }