Created
April 15, 2016 08:29
-
-
Save JohanLarsson/1101d195cf3d78413e545d11e5e71cc5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal static class FormatString | |
{ | |
private static readonly IReadOnlyList<string> Empty = new string[0]; | |
private static readonly ThreadLocal<SortedSet<int>> Indexes = new ThreadLocal<SortedSet<int>>(() => new SortedSet<int>()); | |
/// <summary> | |
/// Call with "first: {0}, second {1} returns new []{"0", "1"}; | |
/// </summary> | |
/// <param name="format">The format string</param> | |
/// <returns>An unordered list of format items found in <paramref name="format"/></returns> | |
internal static IReadOnlyCollection<string> GetFormatItems(string format) | |
{ | |
if (string.IsNullOrEmpty(format)) | |
{ | |
return Empty; | |
} | |
var matches = Regex.Matches(format, @"{(?<index>\d+)}"); | |
var items = matches.Cast<Match>() | |
.Select(x => x.Groups["index"].Value) | |
.ToList(); | |
return items; | |
} | |
internal static int CountUnique(IReadOnlyCollection<string> items) | |
{ | |
if (items.Count == 0) | |
{ | |
return 0; | |
} | |
var indexes = Indexes.Value; | |
indexes.Clear(); | |
foreach (var item in items) | |
{ | |
int index; | |
if (!int.TryParse(item, out index)) | |
{ | |
throw new InvalidOperationException($"Format item is not an int: {item}"); | |
} | |
indexes.Add(index); | |
} | |
return indexes.Count; | |
} | |
/// <summary>Checks that <paramref name="items"/> are 0-n with no gaps.</summary> | |
/// <param name="items">The format items</param> | |
/// <returns>True if <paramref name="items"/> are 0-n with no gaps</returns> | |
internal static bool AreItemsValid(IReadOnlyCollection<string> items) | |
{ | |
if (items.Count == 0) | |
{ | |
return true; | |
} | |
var indexes = Indexes.Value; | |
indexes.Clear(); | |
foreach (var item in items) | |
{ | |
int index; | |
if (!int.TryParse(item, out index)) | |
{ | |
return false; | |
} | |
if (index < 0 || index >= items.Count) | |
{ | |
return false; | |
} | |
indexes.Add(index); | |
} | |
return indexes.Min == 0 && indexes.Max == indexes.Count - 1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class FormatStringTests | |
{ | |
[TestCase("first: {0}, second {1}", "0, 1")] | |
[TestCase("second: {1}, first {0}", "1, 0")] | |
[TestCase("second: {1}, first {0}, first: {0}", "1, 0, 0")] | |
public void GetFormatItems(string format, string expecteds) | |
{ | |
var expected = expecteds.Split(',') | |
.Select(x => x.Trim()) | |
.ToArray(); | |
var actual = FormatString.GetFormatItems(format); | |
CollectionAssert.AreEqual(expected, actual); | |
} | |
[TestCase("0", true)] | |
[TestCase("0, 0, 0", true)] | |
[TestCase("1, 0, 0", true)] | |
[TestCase("0, 0, 1", true)] | |
[TestCase("1", false)] | |
[TestCase("1, 1", false)] | |
[TestCase("0, 2", false)] | |
public void AreItemsValid(string itemsString, bool expected) | |
{ | |
var items = itemsString.Split(',') | |
.Select(x => x.Trim()) | |
.ToArray(); | |
var actual = FormatString.AreItemsValid(items); | |
Assert.AreEqual(expected, actual); | |
actual = FormatString.AreItemsValid(items); | |
Assert.AreEqual(expected, actual); | |
} | |
[Test] | |
public void AreItemsValidWhenEmpty() | |
{ | |
Assert.IsTrue(FormatString.AreItemsValid(new string[0])); | |
} | |
[TestCase("0", 1)] | |
[TestCase("0, 0, 0", 1)] | |
[TestCase("1, 0, 0", 2)] | |
[TestCase("0, 0, 1", 2)] | |
public void Count(string itemsString, int expected) | |
{ | |
var items = itemsString.Split(',') | |
.Select(x => x.Trim()) | |
.ToArray(); | |
var actual = FormatString.CountUnique(items); | |
Assert.AreEqual(expected, actual); | |
actual = FormatString.CountUnique(items); | |
Assert.AreEqual(expected, actual); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment