/// <summary> /// Retrieve a letter lookup dictionary for a given calculation method /// </summary> /// <param name="type">The <see cref="GematriaType"/> for which to retrieve the lookup dictionary</param> /// <returns>Lookup dictionary giving the numeric value for each Hebew character</returns> public static Dictionary <char, int> GetDictionary(GematriaType type) { // only need to generate each type of dictionary once if (!lookupDict.ContainsKey(type)) { lock (dictLock) { if (!lookupDict.ContainsKey(type)) { lookupDict[type] = GenerateDictionary(type); } } } return(lookupDict[type]); }
/// <summary> /// Calculates the gematria value for all Hebrew letters in the given string. /// Ignores all characters that are not Hebrew letters. /// </summary> /// <param name="sourceString">String to evaluate</param> /// <param name="gematriaType"><see cref="T:EllisWeb.Gematria.GematriaType"/> to use for calculation (defaults to Absolute)</param> /// <returns></returns> public static long GetGematriaValue(string sourceString, GematriaType gematriaType = GematriaType.Absolute) { if (string.IsNullOrEmpty(sourceString)) { throw new ArgumentNullException("sourceString"); } long value = 0; var dict = LookupFactory.GetDictionary(gematriaType); foreach (char c in sourceString) { if (dict.ContainsKey(c)) { value += dict[c]; } } return(value); }
private static Dictionary <char, int> GenerateDictionary(GematriaType type) { Dictionary <char, int> dict; if (type == GematriaType.Absolute) { dict = new Dictionary <char, int>(); dict.Add('א', 1); dict.Add('ב', 2); dict.Add('ג', 3); dict.Add('ד', 4); dict.Add('ה', 5); dict.Add('ו', 6); dict.Add('ז', 7); dict.Add('ח', 8); dict.Add('ט', 9); dict.Add('י', 10); dict.Add('כ', 20); dict.Add('ל', 30); dict.Add('מ', 40); dict.Add('נ', 50); dict.Add('ס', 60); dict.Add('ע', 70); dict.Add('פ', 80); dict.Add('צ', 90); dict.Add('ק', 100); dict.Add('ר', 200); dict.Add('ש', 300); dict.Add('ת', 400); dict.Add('ך', 20); dict.Add('ם', 40); dict.Add('ן', 50); dict.Add('ף', 80); dict.Add('ץ', 90); } else // start by calculating the Absolute method. All other methods can be derived from this. { dict = new Dictionary <char, int>(GenerateDictionary(GematriaType.Absolute)); switch (type) { case GematriaType.AbsoluteAlternate: // copy contents of absolute dict // just switch the sofiyot dict['ך'] = 500; dict['ם'] = 600; dict['ן'] = 700; dict['ף'] = 800; dict['ץ'] = 900; break; case GematriaType.AbsoluteNoSofiyot: dict.Remove('ך'); dict.Remove('ם'); dict.Remove('ן'); dict.Remove('ף'); dict.Remove('ץ'); break; case GematriaType.Reduced: // copy contents of alternate dict dict = new Dictionary <char, int>(GenerateDictionary(GematriaType.AbsoluteAlternate)); // go through all items and set to mod 10 of existing value var keysToModify = dict.Where(x => x.Value > 9).Select(x => x.Key).ToList(); foreach (char itemKey in keysToModify) { var val = dict[itemKey]; if (val % 100 == 0) // hundreds { val = val / 100; } else if (val % 10 == 0) // tens { val = val / 10; } // if is not multiple of 10, then is in range of 1-9, so just use the number dict[itemKey] = val; } break; case GematriaType.Ordinal: int index = 1; keysToModify = dict.Select(x => x.Key).ToList(); foreach (char key in keysToModify) { dict[key] = index++; } break; } } return(dict); }
/// <summary> /// Calculates the gematria value for a string that is intended to represent a number (example: a year in the Hebrew calendar or page in a Hebrew book). /// This function expects that the given string will contain only one word, and will throw an error if more than one word is included /// (this is because a string of Hebrew characters representing a number will never consist of multiple words). /// Ignores non-Hebrew characters and punctuation in the given word. /// </summary> /// <param name="sourceString">The string to evaluate</param> /// <param name="gematriaType"><see cref="T:EllisWeb.Gematria.GematriaType"/> to use for calculation (defaults to Absolute)</param> /// <param name="isStrictMode"> /// Should the numeric gematria be evaluated with Strict Mode turned on. Defaults to the global setting /// defined in <see cref="ForceNumericStrictMode"/>. When true this will throw a <see cref="FormatException"/> whenever the numbers at /// the end of the string that are under 100 (ק) are not included in descending numeric order, and do not appear on the exceptions list. /// </param> /// <returns>Number equal to the numeric gematria value of the string provided</returns> /// <remarks> /// This function will infer the division between thousands-groupings of the number by using the following rule: /// Evaluate characters one at a time. It is expected that gematria values within a thousands-grouping will always be the same or equal to the previous value. /// If a value is encountered that is greater than the previous value, it signifies the start of a new thousands-grouping. /// </remarks> public static long GetNumericGematriaValue(string sourceString, GematriaType gematriaType = GematriaType.Absolute, bool?isStrictMode = null) { sourceString = sourceString.Trim(); bool currentStrictMode = isStrictMode ?? ForceNumericStrictMode; if (currentStrictMode) { var stripped = StripSeparatorCharacters(sourceString); if (KnownNumericValues.ContainsKey(stripped)) { return(KnownNumericValues[stripped]); } } if (Regex.IsMatch(sourceString, @"[\s]")) { throw new ArgumentException("Source string contains more than one word", "sourceString"); } var dict = LookupFactory.GetDictionary(gematriaType); List <List <int> > numberStacks = new List <List <int> >(); var currentStack = new List <int>(); numberStacks.Add(currentStack); int prevNum = 0; foreach (char c in sourceString) { if (dict.ContainsKey(c)) { int currentVal = dict[c]; if (currentVal > prevNum && currentStack.Any()) { currentStack = new List <int>(); numberStacks.Add(currentStack); } currentStack.Add(currentVal); prevNum = currentVal; } } // At this point, the first number stack is the highest thousands-grouping. Need to reverse them in order to go from lowest to highest when evaluating. numberStacks.Reverse(); // Go through the number stacks. Multiply the sum of each stack by 1000^X where X is the zero-index value of the current stack int currentStackIndex = 0; long value = 0; bool inHundreds = false; long maxStackSum = 0; foreach (List <int> numberStack in numberStacks) { long stackSum = numberStack.Sum(); if (currentStrictMode) { numberStack.Reverse(); // need to reverse the current stack, in order to preserve the order of items being evaluated foreach (var number in numberStack) { if (number >= 100) { inHundreds = true; } if (!inHundreds && number < maxStackSum) { throw new FormatException("In Strict Mode, trailing values less than 100 (ק) must appear in the proper order"); } maxStackSum = Math.Max(maxStackSum, number); } } var stackMultiplier = Math.Pow(1000, currentStackIndex++); var adjustedStackSum = Convert.ToInt64(stackSum * stackMultiplier); value += adjustedStackSum; } return(value); }