/// <summary> /// A specifier is some block of text contained in < >, such as '<a1>'. While specifiers always follow the form /// 'labelNUMBER', this parser will happily accept specifiers missing one or both parts. /// </summary> /// <param name="From"></param> /// <param name="Type">Out parameter. Set to the label parsed from the specifier. Blank if no label found.</param> /// <param name="Index">Out parameter. Set to the value of the integer index parsed from the specifier. 0 if no index found.</param> /// <returns>True if parsing succeeded, false if parsing failed</returns> internal static bool ReadSpecifier(StringIterator From, out String Type, out int Index) { Type = ""; Index = 0; if (From.Next != '<') { return(false); } From.Advance(); while (!From.AtEnd && From.Next != '>' && !IsDigit(From.Next)) { Type += From.Next; From.Advance(); } if (IsDigit(From.Next)) { if (!ReadNumber(From, out Index)) { return(false); } } if (From.AtEnd || From.Next != '>') { return(false); } From.Advance(); return(true); }
/// <summary> /// Parse and format a message intended for a specific recipient. /// </summary> /// <param name="Recipient"></param> /// <param name="Message">The message, possibly containing specifiers.</param> /// <param name="Objects">Specifier indicies refer to this list of objects.</param> /// <returns></returns> public static String FormatParserMessage(MudObject Recipient, String Message, PossibleMatch Objects) { //A leading @ indicates that the message should be interpretted as an entry in the global message table. if (Message[0] == '@') { Message = Core.GetMessage(Message.Substring(1)); } var formattedMessage = new StringBuilder(); var iterator = new StringIterator(Message); while (!iterator.AtEnd) { if (iterator.Next == '<') //We have located a specifier. { if (MessageFormatParser.ReadIdentifier(iterator, out var propertyName) && Objects.ContainsKey(propertyName)) { formattedMessage.Append(Objects[propertyName] == null ? "%NULL" : Objects[propertyName].ToString()); } } else { formattedMessage.Append(iterator.Next); iterator.Advance(); } } Message = formattedMessage.ToString(); formattedMessage.Clear(); iterator = new StringIterator(Message); //Apply the ^ transform: Capitalize the letter following the ^ and remove the ^. while (!iterator.AtEnd) { if (iterator.Next == '^') { iterator.Advance(); if (iterator.AtEnd) { break; } formattedMessage.Append(new String(iterator.Next, 1).ToUpper()); iterator.Advance(); } else { formattedMessage.Append(iterator.Next); iterator.Advance(); } } return(formattedMessage.ToString()); }
/// <summary> /// Parses a number, which may be multiple digits. /// </summary> /// <param name="From"></param> /// <param name="Number"></param> /// <returns></returns> private static bool ReadNumber(StringIterator From, out int Number) { Number = 0; var digitString = ""; while (!From.AtEnd && IsDigit(From.Next)) { digitString += From.Next; From.Advance(); } if (digitString.Length == 0) { return(false); } Number = Convert.ToInt32(digitString); return(true); }
internal static bool ReadIdentifier(StringIterator From, out String Into) { Into = ""; if (From.Next != '<') { return(false); } From.Advance(); while (!From.AtEnd && From.Next != '>') { Into += From.Next; From.Advance(); } if (From.AtEnd) { return(false); } From.Advance(); return(true); }
/// <summary> /// Parse and format a message intended for a specific recipient. /// </summary> /// <param name="Recipient"></param> /// <param name="Message">The message, possibly containing specifiers.</param> /// <param name="Objects">Specifier indicies refer to this list of objects.</param> /// <returns></returns> public static String FormatMessage(Actor Recipient, String Message, params Object[] Objects) { //A leading @ indicates that the message should be interpretted as an entry in the global message table. if (Message[0] == '@') Message = Core.GetMessage(Message.Substring(1)); var formattedMessage = new StringBuilder(); var iterator = new StringIterator(Message); while (!iterator.AtEnd) { if (iterator.Next == '<') //We have located a specifier. { var type = ""; var index = 0; if (MessageFormatParser.ReadSpecifier(iterator, out type, out index)) { if (index < 0 || index >= Objects.Length) continue; //A blank in the output is preferable to crashing. #region Expand Specifier if (type == "the" && Objects[index] is MudObject) { //'the' overrides the object's article property. formattedMessage.Append(GlobalRules.ConsiderValueRule<String>("printed name", Recipient, Objects[index], "the")); } else if (type == "a" && Objects[index] is MudObject) { formattedMessage.Append(GlobalRules.ConsiderValueRule<String>("printed name", Recipient, Objects[index], (Objects[index] as MudObject).Article)); } else if (type == "l") //No connective clause is used for this style of list. eg 1, 2, 3. { FormatList(Recipient, Objects[index], formattedMessage, ""); } else if (type == "lor") //Use or. eg 1, 2, or 3. { FormatList(Recipient, Objects[index], formattedMessage, "or"); } else if (type == "land") //Use and. eg 1, 2, and 3. { FormatList(Recipient, Objects[index], formattedMessage, "and"); } else if (type == "lnor") //Use nor. eg 1, 2, nor 3. { FormatList(Recipient, Objects[index], formattedMessage, "nor"); } else if (type == "s") { formattedMessage.Append(Objects[index].ToString()); } #endregion } } else { formattedMessage.Append(iterator.Next); iterator.Advance(); } } Message = formattedMessage.ToString(); formattedMessage.Clear(); iterator = new StringIterator(Message); //Apply the ^ transform: Capitalize the letter following the ^ and remove the ^. while (!iterator.AtEnd) { if (iterator.Next == '^') { iterator.Advance(); if (iterator.AtEnd) break; formattedMessage.Append(new String(iterator.Next, 1).ToUpper()); iterator.Advance(); } else { formattedMessage.Append(iterator.Next); iterator.Advance(); } } return formattedMessage.ToString(); }
/// <summary> /// Parses a number, which may be multiple digits. /// </summary> /// <param name="From"></param> /// <param name="Number"></param> /// <returns></returns> private static bool ReadNumber(StringIterator From, out int Number) { Number = 0; var digitString = ""; while (!From.AtEnd && IsDigit(From.Next)) { digitString += From.Next; From.Advance(); } if (digitString.Length == 0) return false; Number = Convert.ToInt32(digitString); return true; }
/// <summary> /// A specifier is some block of text contained in < >, such as '<a1>'. While specifiers always follow the form /// 'labelNUMBER', this parser will happily accept specifiers missing one or both parts. /// </summary> /// <param name="From"></param> /// <param name="Type">Out parameter. Set to the label parsed from the specifier. Blank if no label found.</param> /// <param name="Index">Out parameter. Set to the value of the integer index parsed from the specifier. 0 if no index found.</param> /// <returns>True if parsing succeeded, false if parsing failed</returns> internal static bool ReadSpecifier(StringIterator From, out String Type, out int Index) { Type = ""; Index = 0; if (From.Next != '<') return false; From.Advance(); while (!From.AtEnd && From.Next != '>' && !IsDigit(From.Next)) { Type += From.Next; From.Advance(); } if (IsDigit(From.Next)) if (!ReadNumber(From, out Index)) return false; if (From.AtEnd || From.Next != '>') return false; From.Advance(); return true; }
/// <summary> /// Parse and format a message intended for a specific recipient. /// </summary> /// <param name="Recipient"></param> /// <param name="Message">The message, possibly containing specifiers.</param> /// <param name="Objects">Specifier indicies refer to this list of objects.</param> /// <returns></returns> public static String FormatMessage(MudObject Recipient, String Message, params Object[] Objects) { //A leading @ indicates that the message should be interpretted as an entry in the global message table. if (Message[0] == '@') { Message = Core.GetMessage(Message.Substring(1)); } var formattedMessage = new StringBuilder(); var iterator = new StringIterator(Message); while (!iterator.AtEnd) { if (iterator.Next == '<') //We have located a specifier. { var type = ""; var index = 0; if (MessageFormatParser.ReadSpecifier(iterator, out type, out index)) { if (index < 0 || index >= Objects.Length) { continue; //A blank in the output is preferable to crashing. } #region Expand Specifier if (type == "the" && Objects[index] is MudObject) { //'the' overrides the object's article property. formattedMessage.Append(GlobalRules.ConsiderValueRule <String>("printed name", Recipient, Objects[index], "the")); } else if (type == "a" && Objects[index] is MudObject) { formattedMessage.Append(GlobalRules.ConsiderValueRule <String>("printed name", Recipient, Objects[index], (Objects[index] as MudObject).GetProperty <String>("article"))); } else if (type == "l") //No connective clause is used for this style of list. eg 1, 2, 3. { FormatList(Recipient, Objects[index], formattedMessage, ""); } else if (type == "lor") //Use or. eg 1, 2, or 3. { FormatList(Recipient, Objects[index], formattedMessage, "or"); } else if (type == "land") //Use and. eg 1, 2, and 3. { FormatList(Recipient, Objects[index], formattedMessage, "and"); } else if (type == "lnor") //Use nor. eg 1, 2, nor 3. { FormatList(Recipient, Objects[index], formattedMessage, "nor"); } else if (type == "s") { if (Objects[index] == null) { formattedMessage.Append("%NULL%"); } else { formattedMessage.Append(Objects[index].ToString()); } } #endregion } } else { formattedMessage.Append(iterator.Next); iterator.Advance(); } } Message = formattedMessage.ToString(); formattedMessage.Clear(); iterator = new StringIterator(Message); //Apply the ^ transform: Capitalize the letter following the ^ and remove the ^. while (!iterator.AtEnd) { if (iterator.Next == '^') { iterator.Advance(); if (iterator.AtEnd) { break; } formattedMessage.Append(new String(iterator.Next, 1).ToUpper()); iterator.Advance(); } else { formattedMessage.Append(iterator.Next); iterator.Advance(); } } return(formattedMessage.ToString()); }