/// <summary> /// Processes a list of format tokens into a string /// </summary> /// <param name="tokens">List of tokens to turn into a string</param> /// <param name="replacements">An <see cref="IDictionary"/> with keys and values to inject into the formatted result</param> /// <param name="missingKeyBehaviour">The behaviour to use when the format string contains a parameter that is not present in the lookup dictionary</param> /// <param name="fallbackReplacementValue">When the <see cref="MissingKeyBehaviour.ReplaceWithFallback"/> is specified, this string is used as a fallback replacement value when the parameter is present in the lookup dictionary.</param> /// <returns>The processed result of joining the tokens with the replacement dictionary.</returns> public static string ProcessTokens( IEnumerable <FormatToken> tokens, Func <string, ReplacementResult> handler, MissingKeyBehaviour missingKeyBehaviour, object fallbackReplacementValue, int outputLengthHint) { // create a StringBuilder to hold the resultant output string // use the input hint as the initial size StringBuilder resultBuilder = new StringBuilder(outputLengthHint); foreach (FormatToken thisToken in tokens) { if (thisToken.TokenType == TokenType.Text) { // token is a text token // add the token to the result string builder resultBuilder.Append(thisToken.SourceString, thisToken.StartIndex, thisToken.Length); } else if (thisToken.TokenType == TokenType.Parameter) { // token is a parameter token // perform parameter logic now. // append the replacement for this parameter ReplacementResult replacementResult = handler(thisToken.Value); if (replacementResult.Success) { // the key exists, add the replacement value // this does nothing if replacement value is null resultBuilder.Append(replacementResult.Value); } else { // the key does not exist, handle this using the missing key behaviour specified. switch (missingKeyBehaviour) { case MissingKeyBehaviour.ThrowException: // the key was not found as a possible replacement, throw exception throw new KeyNotFoundException($"The parameter \"{thisToken.Value}\" was not present in the lookup dictionary"); case MissingKeyBehaviour.ReplaceWithFallback: resultBuilder.Append(fallbackReplacementValue); break; case MissingKeyBehaviour.Ignore: // the replacement value is the input key as a parameter. // use source string and start/length directly with append rather than // parameter.ParameterKey to avoid allocating an extra string resultBuilder.Append(thisToken.SourceString, thisToken.StartIndex, thisToken.Length); break; } } } } // return the resultant string return(resultBuilder.ToString()); }
public static FormattableString FormattableWith( string formatString, Func <string, ReplacementResult> handler, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, object fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { // get the parameters from the format string IEnumerable <FormatToken> tokens = FormatHelpers.Tokenize(formatString, openBraceChar, closeBraceChar); return(FormatHelpers.ProcessTokensIntoFormattableString(tokens, handler, missingKeyBehaviour, fallbackReplacementValue, formatString.Length * 2)); }
public static FormattableString FormattableWith( string formatString, object replacementObject, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, object fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { return(FormattableWith(formatString, key => FromReplacementObject(key, replacementObject), missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
public static FormattableString FormattableWith( string formatString, IDictionary <string, string> replacements, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, string fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { return(FormattableWith( formatString, key => new ReplacementResult(replacements.TryGetValue(key, out string value), value), missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
/// <summary> /// Produces a <see cref="FormattableString"/> representing the input format string. /// </summary> /// <param name="formatString">The format string, containing keys like {foo}</param> /// <param name="handler">A handler function that transforms each parameter into a <see cref="ReplacementResult"/></param> /// <param name="missingKeyBehaviour">The behaviour to use when the format string contains a parameter that cannot be replaced by the handler</param> /// <param name="fallbackReplacementValue">When the <see cref="MissingKeyBehaviour.ReplaceWithFallback"/> is specified, this object is used as a fallback replacement value.</param> /// <param name="openBraceChar">The character used to begin parameters</param> /// <param name="closeBraceChar">The character used to end parameters</param> /// <returns>The resultant <see cref="FormattableString"/></returns> public static FormattableString FormattableWith( this string formatString, Func <string, ReplacementResult> handler, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, object fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { return(FormatWithMethods.FormattableWith( formatString, handler, missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
/// <summary> /// Produces a <see cref="FormattableString"/> representing the input format string. /// </summary> /// <param name="formatString">The format string, containing keys like {foo}</param> /// <param name="replacements">An <see cref="IDictionary"/> with keys and values to inject into the string</param> /// <param name="missingKeyBehaviour">The behaviour to use when the format string contains a parameter that is not present in the lookup dictionary</param> /// <param name="fallbackReplacementValue">When the <see cref="MissingKeyBehaviour.ReplaceWithFallback"/> is specified, this string is used as a fallback replacement value when the parameter is present in the lookup dictionary.</param> /// <param name="openBraceChar">The character used to begin parameters</param> /// <param name="closeBraceChar">The character used to end parameters</param> /// <returns>The resultant <see cref="FormattableString"/></returns> public static FormattableString FormattableWith( this string formatString, IDictionary <string, object> replacements, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, object fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { return(FormatWithMethods.FormattableWith( formatString, replacements, missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
/// <summary> /// Formats a string with the values of the dictionary. /// </summary> /// <param name="formatString">The format string, containing keys like {foo}</param> /// <param name="replacements">An <see cref="IDictionary"/> with keys and values to inject into the string</param> /// <param name="missingKeyBehaviour">The behaviour to use when the format string contains a parameter that is not present in the lookup dictionary</param> /// <param name="fallbackReplacementValue">When the <see cref="MissingKeyBehaviour.ReplaceWithFallback"/> is specified, this string is used as a fallback replacement value when the parameter is present in the lookup dictionary.</param> /// <param name="openBraceChar">The character used to begin parameters</param> /// <param name="closeBraceChar">The character used to end parameters</param> /// <returns>The formatted string</returns> public static string FormatWith( this string formatString, IDictionary <string, string> replacements, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, string fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { // wrap the IDictionary<string, string> in a wrapper Dictionary class that casts the values to objects as needed return(FormatWithMethods.FormatWith( formatString, replacements, missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
/// <summary> /// Formats a string with the values given by the properties on an input object. /// </summary> /// <param name="formatString">The format string, containing keys like {foo}</param> /// <param name="replacementObject">The object whose properties should be injected in the string</param> /// <param name="missingKeyBehaviour">The behaviour to use when the format string contains a parameter that is not present in the lookup dictionary</param> /// <param name="fallbackReplacementValue">When the <see cref="MissingKeyBehaviour.ReplaceWithFallback"/> is specified, this string is used as a fallback replacement value when the parameter is present in the lookup dictionary.</param> /// <param name="openBraceChar">The character used to begin parameters</param> /// <param name="closeBraceChar">The character used to end parameters</param> /// <returns>The formatted string</returns> public static string FormatWith( this string formatString, object replacementObject, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, object fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { // wrap the type object in a wrapper Dictionary class that exposes the properties as dictionary keys via reflection return(FormatWithMethods.FormatWith( formatString, replacementObject, missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
public static string FormatWith( string formatString, object replacementObject, MissingKeyBehaviour missingKeyBehaviour = MissingKeyBehaviour.ThrowException, object fallbackReplacementValue = null, char openBraceChar = '{', char closeBraceChar = '}') { if (replacementObject == null) { throw new ArgumentNullException(nameof(replacementObject)); } return(FormatWith(formatString, (key, format) => FromReplacementObject(key, replacementObject), missingKeyBehaviour, fallbackReplacementValue, openBraceChar, closeBraceChar)); }
/// <summary> /// Processes a list of format tokens into a string /// </summary> /// <param name="tokens">List of tokens to turn into a string</param> /// <param name="replacements">An <see cref="IDictionary"/> with keys and values to inject into the formatted result</param> /// <param name="missingKeyBehaviour">The behaviour to use when the format string contains a parameter that is not present in the lookup dictionary</param> /// <param name="fallbackReplacementValue">When the <see cref="MissingKeyBehaviour.ReplaceWithFallback"/> is specified, this string is used as a fallback replacement value when the parameter is present in the lookup dictionary.</param> /// <returns>The processed result of joining the tokens with the replacement dictionary.</returns> public static FormattableString ProcessTokensIntoFormattableString( IEnumerable <FormatToken> tokens, Func <string, ReplacementResult> handler, MissingKeyBehaviour missingKeyBehaviour, object fallbackReplacementValue, int outputLengthHint) { List <object> replacementParams = new List <object>(); // create a StringBuilder to hold the resultant output string // use the input hint as the initial size StringBuilder resultBuilder = new StringBuilder(outputLengthHint); // this is the index of the current placeholder in the composite format string int placeholderIndex = 0; foreach (FormatToken thisToken in tokens) { if (thisToken.TokenType == TokenType.Text) { // token is a text token. // add the token to the result string builder. // because this text is going into a standard composite format string, // any instaces of { or } must be escaped with {{ and }} resultBuilder.AppendWithEscapedBrackets(thisToken.SourceString, thisToken.StartIndex, thisToken.Length); } else if (thisToken.TokenType == TokenType.Parameter) { // token is a parameter token // perform parameter logic now. var tokenKey = thisToken.Value; string format = null; var separatorIdx = tokenKey.IndexOf(":", StringComparison.Ordinal); if (separatorIdx > -1) { tokenKey = thisToken.Value.Substring(0, separatorIdx); format = thisToken.Value.Substring(separatorIdx + 1); } // append the replacement for this parameter ReplacementResult replacementResult = handler(tokenKey); string IndexAndFormat() { if (string.IsNullOrWhiteSpace(format)) { return("{" + placeholderIndex + "}"); } return("{" + placeholderIndex + ":" + format + "}"); } // append the replacement for this parameter if (replacementResult.Success) { // Instead of appending the replacement value directly as before, // append the next placeholder with the current placeholder index. // Add the actual replacement format item into the replacement values. resultBuilder.Append(IndexAndFormat()); placeholderIndex++; replacementParams.Add(replacementResult.Value); } else { // the key does not exist, handle this using the missing key behaviour specified. switch (missingKeyBehaviour) { case MissingKeyBehaviour.ThrowException: // the key was not found as a possible replacement, throw exception throw new KeyNotFoundException($"The parameter \"{thisToken.Value}\" was not present in the lookup dictionary"); case MissingKeyBehaviour.ReplaceWithFallback: // Instead of appending the replacement value directly as before, // append the next placeholder with the current placeholder index. // Add the actual replacement format item into the replacement values. resultBuilder.Append(IndexAndFormat()); placeholderIndex++; replacementParams.Add(fallbackReplacementValue); break; case MissingKeyBehaviour.Ignore: resultBuilder.AppendWithEscapedBrackets(thisToken.SourceString, thisToken.StartIndex, thisToken.Length); break; } } } } // return the resultant string return(FormattableStringFactory.Create(resultBuilder.ToString(), replacementParams.ToArray())); }