Skip to content
34 changes: 10 additions & 24 deletions FormatWith/Internal/FormatHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -43,29 +43,22 @@ public static string ProcessTokens(
{
// 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);
}
TokenInformation tokenInfo = new TokenInformation(thisToken.Value);

// append the replacement for this parameter
ReplacementResult replacementResult = handler(tokenKey, format);
ReplacementResult replacementResult = handler(tokenInfo.TokenKey, tokenInfo.Format);

if (replacementResult.Success)
{
// the key exists, add the replacement value
// this does nothing if replacement value is null
if (string.IsNullOrWhiteSpace(format))
if (string.IsNullOrWhiteSpace(tokenInfo.FormatString))
{
resultBuilder.Append(replacementResult.Value);
}
else
{
resultBuilder.AppendFormat("{0:" + format + "}", replacementResult.Value);
resultBuilder.AppendFormat("{0" + tokenInfo.FormatString + "}", replacementResult.Value);
}
}
else
Expand Down Expand Up @@ -133,26 +126,19 @@ public static FormattableString ProcessTokensIntoFormattableString(
{
// 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);
}
TokenInformation tokenInfo = new TokenInformation(thisToken.Value);

// append the replacement for this parameter
ReplacementResult replacementResult = handler(tokenKey);
ReplacementResult replacementResult = handler(tokenInfo.TokenKey);

string IndexAndFormat()
{
if (string.IsNullOrWhiteSpace(format))
if (string.IsNullOrWhiteSpace(tokenInfo.FormatString))
{
return "{" + placeholderIndex + "}";
}

return "{" + placeholderIndex + ":" + format + "}";
return "{" + placeholderIndex + tokenInfo.FormatString + "}";
}

// append the replacement for this parameter
Expand Down
192 changes: 192 additions & 0 deletions FormatWith/TokenInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
namespace FormatWith
{

/// <summary>
/// Encapsulates the token-parsing logic and values, ensuring consistent behavior and allowing them to be passed to handlers more concisely.
/// </summary>
public class TokenInformation
{

#region Static & Const

///// <summary>
///// A regular expression to parse the token
///// </summary>
//private static readonly System.Text.RegularExpressions.Regex _parseRegEx = new System.Text.RegularExpressions.Regex(@"(?<token>([^,;:\s]+))(,(?<alignment>-?\d+))?(:(?<format>.*))?", System.Text.RegularExpressions.RegexOptions.Compiled);

#endregion

#region Properties

/// <summary>
/// The raw token parsed.
/// </summary>
public string RawToken { get; private set; }

/// <summary>
/// The token key.
/// </summary>
public string TokenKey { get; private set; }

/// <summary>
/// The alignment indicator
/// </summary>
public string Alignment { get; private set; }

/// <summary>
/// The base format string. (no alignment)
/// </summary>
public string Format { get; private set; }

private string _formatString = null;
/// <summary>
/// The full composite formatting string. [,align][:format]
/// </summary>
public string FormatString
{
get
{
if (null == this._formatString)
{
this._formatString = string.Concat((!string.IsNullOrEmpty(this.Alignment) ? $",{this.Alignment}" : string.Empty), (!string.IsNullOrEmpty(this.Format) ? $":{this.Format}" : string.Empty));
}
return (this._formatString);
}
}

#endregion

#region Constructors

/// <summary>
/// Parses token information from a raw token string value.
/// </summary>
/// <param name="rawToken">The raw token string.</param>
/// <remarks>IndexOf/Substring version of parser based on existing code</remarks>
public TokenInformation(string rawToken)
{
this.RawToken = rawToken;
this.Format = null;
this.Alignment = null;

// Parse out the format
var separatorIdx = rawToken.IndexOf(":", System.StringComparison.Ordinal);
if (separatorIdx > -1)
{
this.Format = rawToken.Substring(separatorIdx + 1);
rawToken = rawToken.Substring(0, separatorIdx);
}

// Parse out alignment
var alignmentIdx = rawToken.LastIndexOf(",", System.StringComparison.Ordinal);
if (alignmentIdx > -1)
{
this.Alignment = rawToken.Substring(alignmentIdx + 1);
rawToken = rawToken.Substring(0, alignmentIdx);
}

// Grab the token key
this.TokenKey = rawToken;
}

///// <summary>
///// Parses token information from a raw token string value.
///// </summary>
///// <param name="rawToken">The raw token string.</param>
///// <remarks>RegEx version of parser, for performance comparison, and in case someone else knows how to optimize it more</remarks>
//public TokenInformation(string rawToken, bool ignoreThisParameterItIsHereForPerformanceComparisons)
//{
// this.RawToken = rawToken;
// this.Alignment = null;
// this.Format = null;
//
// System.Text.RegularExpressions.Match results = _parseRegEx.Match(rawToken);
// if(results.Success)
// {
// this.TokenKey = results.Groups["token"].Value;
// this.Alignment = results.Groups["alignment"].Value;
// this.Format = results.Groups["format"].Value;
// }
//}

#endregion

#region Methods

private static string BuildString(string tokenKey, string alignment, string format)
{
string rawToken = string.Concat(tokenKey, (!string.IsNullOrEmpty(alignment) ? $",{alignment}" : string.Empty), (!string.IsNullOrEmpty(format) ? $":{format}" : string.Empty));
return (rawToken);
}

/// <summary>
/// Builds a raw token string given the desired tokenKey and format
/// </summary>
/// <param name="tokenKey">The key value for the token.</param>
/// <param name="alignment">The left- or right-padding indicator desired.</param>
/// <param name="format">The format string.</param>
/// <returns></returns>
public static string BuildString(string tokenKey, int? alignment, string format)
{
return (TokenInformation.BuildString(tokenKey, alignment.HasValue ? $"{alignment}" : string.Empty, format));
}

/// <summary>
/// Builds a raw token string given the desired tokenKey and format
/// </summary>
/// <param name="tokenKey">The key value for the token.</param>
/// <param name="format">The format string.</param>
/// <returns></returns>
public static string BuildString(string tokenKey, string format)
{
return (TokenInformation.BuildString(tokenKey, (int?)null, format));
}

/// <summary>
/// Builds a raw token string given the desired tokenKey and format
/// </summary>
/// <param name="tokenKey">The key value for the token.</param>
/// <param name="alignment">The left- or right-padding indicator desired.</param>
/// <returns></returns>
public static string BuildString(string tokenKey, int? alignment)
{
return (TokenInformation.BuildString(tokenKey, alignment, null));
}

/// <summary>
/// Builds a raw token string given the desired tokenKey and format
/// </summary>
/// <param name="tokenKey">The key value for the token.</param>
/// <returns></returns>
public static string BuildString(string tokenKey)
{
return(TokenInformation.BuildString(tokenKey, (int?)null, null));
}

/// <summary>
/// Builds a TokenInfo object given the desired tokenKey and format
/// </summary>
/// <param name="tokenKey">The key value for the token.</param>
/// <param name="alignment">The left- or right-padding indicator desired.</param>
/// <param name="format">The format string.</param>
/// <returns></returns>
public static TokenInformation Build(string tokenKey, int? alignment, string format)
{
return (new TokenInformation(TokenInformation.BuildString(tokenKey, alignment, format)));
}

/// <summary>
/// Builds a TokenInfo object given the desired tokenKey and format
/// </summary>
/// <param name="tokenKey">The key value for the token.</param>
/// <param name="format">The format string.</param>
/// <returns></returns>
public static TokenInformation Build(string tokenKey, string format)
{
return (TokenInformation.Build(tokenKey, null, format));
}

#endregion

} // end class
} // end namespace
2 changes: 1 addition & 1 deletion FormatWithTests/TestStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static class TestStrings
public static readonly string TestFormat6 = "abc{Replacement1:upper}";
public static readonly string TestFormat6Composite = "abc{0:upper}";
public static readonly string TestFormat6Solution = $"abc{Replacement1.ToUpper()}";

public static readonly string TestFormat7 = "Today is {Today:YYYYMMDD HH:mm}";
public static readonly string TestFormat7Composite = "Today is {0:YYYYMMDD HH:mm}";
public static readonly DateTime TestFormat7Date = new DateTime(2018, 10, 30, 17, 25, 0);
Expand Down
Loading