为时间跨度 C# 生成所有可能的字符串时间格式
Generate all possible string time formats for timespan C#
我正在尝试生成以下 TimeSpan
字符串格式,其中包含“h:m:s:f”,时、分和秒最多 2 位,0 到 3 位毫秒。
所需格式:
hh:m:ss:fff
h:mm:s
hh:mm:ss
h:m:s:ff
等等。
我正在尝试使用递归来做到这一点,但我很难做到这一点我尝试了以下操作:
//Key - minimum digits left
//Value starting digits count
private static Dictionary<char, KeyValuePair<int, int>> replacements =
new Dictionary<char, KeyValuePair<int, int>>
{
['f'] = new KeyValuePair<int, int>(0, 3),
['s'] = new KeyValuePair<int, int>(1, 2),
['m'] = new KeyValuePair<int, int>(1, 2),
['h'] = new KeyValuePair<int, int>(1, 2)
};
private static char[] chars = new[] { 'f', 's', 'm', 'h' };
private static string baseTemplate = @"hh\:mm\:ss\:fff";
static IEnumerable<string> GetFormats(string template, int startIndex = 0, int endIndex = 0, List<string> formats = null)
{
if (formats == null)
{
formats = new List<string>{template};
}
string copyTemplate = template;
char currentChar = chars[startIndex];
int indexToRemove = copyTemplate.IndexOf(currentChar);
for (int i = 0; i < replacements[currentChar].Value - replacements[currentChar].Key; i++)
{
copyTemplate = copyTemplate.Remove(indexToRemove, 1);
formats.Add(copyTemplate.TrimEnd('\', '.', ':'));
}
if (startIndex == chars.Length - 1 && endIndex == chars.Length - 1)
{
return formats;
}
if (startIndex == 0)
{
return GetFormats(baseTemplate, endIndex + 1, endIndex + 1, formats);
}
return GetFormats(copyTemplate, startIndex - 1, endIndex, formats);
}
但它似乎不起作用,我也有一个工作版本,它基本上是一个使用 for 循环的暴力解决方案:
private static List<string> GetFormats(List<string> separators)
{
List<string> formats = new List<string>();
for (int i = 0; i < separators.Count; i++)
{
string format = string.Empty;
for (int hours = 1; hours <= 2; hours++)
{
format += "h";
string hoursCopy = format;
format += @"\:";
for (int minutes = 1; minutes <= 2; minutes++)
{
format += "m";
string minutesCopy = format;
format += @"\:";
for (int seconds = 1; seconds <= 2; seconds++)
{
format += "s";
string secondsCopy = format;
format += $@"\{separators[i]}";
for (int miliseconds = 0; miliseconds <= 3; miliseconds++)
{
formats.Add(format.TrimEnd('\', '.', ':'));
format += "f";
}
format = secondsCopy;
}
format = minutesCopy;
}
format = hoursCopy;
}
}
return formats;
}
调用:
GetFormats(new[] { ":" })
如何修复我的递归方法?
不是想成为一个聪明人,OP,但如果这是一个需要我的团队解决的现实世界问题,我们会这样做:
static public List<string> GetFormats()
{
return new List<string>
{
@"h\:mm\:ss\.fff",
@"h\:mm\:ss\.ff",
@"h\:mm\:ss\.f",
@"h\:mm\:ss",
@"h\:mm",
@"hh\:mm\:ss\.fff",
@"hh\:mm\:ss\.ff",
@"hh\:mm\:ss\.f",
@"hh\:mm\:ss",
@"hh\:mm"
};
}
这是一个一次性的问题,可以在纸上轻松解决。假设没有一些未说明的要求(例如与国际化的兼容性),则自动化的需求为零。
如果你坚持生成它(并坚持分钟或秒可以用一个数字表示,我肯定从未见过),你可以像这样用一点 LINQ 来完成它:
using System;
using System.Linq;
using System.Collections.Generic;
static public class ExtensionMethods
{
static public IEnumerable<string> AddPossibilities(this IEnumerable<string> input, string symbol, string prefix, int minLength, int maxLength)
{
return input
.SelectMany
(
stringSoFar =>
Enumerable.Range
(
minLength,
maxLength-minLength+1
)
.Select
(
length => stringSoFar +
(
length == 0 ? "" : prefix
+ Enumerable.Range(0, length)
.Select(i => symbol)
.Aggregate((c, n) => c + n)
)
)
);
}
}
public class Program
{
public static void Main()
{
var results = new List<string> { "" }; //Empty to start
var list = results
.AddPossibilities("h", @"" , 1, 2)
.AddPossibilities("m", @"\:" , 1, 2)
.AddPossibilities("s", @"\:" , 1, 2)
.AddPossibilities("f", @"\." , 0, 3);
var timeSpan = new TimeSpan(0,1,2,3,4);
foreach (var s in list)
{
Console.WriteLine(timeSpan.ToString(s));
}
}
}
输出:
1:2:3
1:2:3.0
1:2:3.00
1:2:3.004
1:2:03
1:2:03.0
1:2:03.00
1:2:03.004
1:02:3
1:02:3.0
1:02:3.00
1:02:3.004
1:02:03
1:02:03.0
1:02:03.00
1:02:03.004
01:2:3
01:2:3.0
01:2:3.00
01:2:3.004
01:2:03
01:2:03.0
01:2:03.00
01:2:03.004
01:02:3
01:02:3.0
01:02:3.00
01:02:3.004
01:02:03
01:02:03.0
01:02:03.00
01:02:03.004
Click here for working code 在 DotNetFiddle 上。
我正在尝试生成以下 TimeSpan
字符串格式,其中包含“h:m:s:f”,时、分和秒最多 2 位,0 到 3 位毫秒。
所需格式:
hh:m:ss:fff
h:mm:s
hh:mm:ss
h:m:s:ff
等等。
我正在尝试使用递归来做到这一点,但我很难做到这一点我尝试了以下操作:
//Key - minimum digits left
//Value starting digits count
private static Dictionary<char, KeyValuePair<int, int>> replacements =
new Dictionary<char, KeyValuePair<int, int>>
{
['f'] = new KeyValuePair<int, int>(0, 3),
['s'] = new KeyValuePair<int, int>(1, 2),
['m'] = new KeyValuePair<int, int>(1, 2),
['h'] = new KeyValuePair<int, int>(1, 2)
};
private static char[] chars = new[] { 'f', 's', 'm', 'h' };
private static string baseTemplate = @"hh\:mm\:ss\:fff";
static IEnumerable<string> GetFormats(string template, int startIndex = 0, int endIndex = 0, List<string> formats = null)
{
if (formats == null)
{
formats = new List<string>{template};
}
string copyTemplate = template;
char currentChar = chars[startIndex];
int indexToRemove = copyTemplate.IndexOf(currentChar);
for (int i = 0; i < replacements[currentChar].Value - replacements[currentChar].Key; i++)
{
copyTemplate = copyTemplate.Remove(indexToRemove, 1);
formats.Add(copyTemplate.TrimEnd('\', '.', ':'));
}
if (startIndex == chars.Length - 1 && endIndex == chars.Length - 1)
{
return formats;
}
if (startIndex == 0)
{
return GetFormats(baseTemplate, endIndex + 1, endIndex + 1, formats);
}
return GetFormats(copyTemplate, startIndex - 1, endIndex, formats);
}
但它似乎不起作用,我也有一个工作版本,它基本上是一个使用 for 循环的暴力解决方案:
private static List<string> GetFormats(List<string> separators)
{
List<string> formats = new List<string>();
for (int i = 0; i < separators.Count; i++)
{
string format = string.Empty;
for (int hours = 1; hours <= 2; hours++)
{
format += "h";
string hoursCopy = format;
format += @"\:";
for (int minutes = 1; minutes <= 2; minutes++)
{
format += "m";
string minutesCopy = format;
format += @"\:";
for (int seconds = 1; seconds <= 2; seconds++)
{
format += "s";
string secondsCopy = format;
format += $@"\{separators[i]}";
for (int miliseconds = 0; miliseconds <= 3; miliseconds++)
{
formats.Add(format.TrimEnd('\', '.', ':'));
format += "f";
}
format = secondsCopy;
}
format = minutesCopy;
}
format = hoursCopy;
}
}
return formats;
}
调用:
GetFormats(new[] { ":" })
如何修复我的递归方法?
不是想成为一个聪明人,OP,但如果这是一个需要我的团队解决的现实世界问题,我们会这样做:
static public List<string> GetFormats()
{
return new List<string>
{
@"h\:mm\:ss\.fff",
@"h\:mm\:ss\.ff",
@"h\:mm\:ss\.f",
@"h\:mm\:ss",
@"h\:mm",
@"hh\:mm\:ss\.fff",
@"hh\:mm\:ss\.ff",
@"hh\:mm\:ss\.f",
@"hh\:mm\:ss",
@"hh\:mm"
};
}
这是一个一次性的问题,可以在纸上轻松解决。假设没有一些未说明的要求(例如与国际化的兼容性),则自动化的需求为零。
如果你坚持生成它(并坚持分钟或秒可以用一个数字表示,我肯定从未见过),你可以像这样用一点 LINQ 来完成它:
using System;
using System.Linq;
using System.Collections.Generic;
static public class ExtensionMethods
{
static public IEnumerable<string> AddPossibilities(this IEnumerable<string> input, string symbol, string prefix, int minLength, int maxLength)
{
return input
.SelectMany
(
stringSoFar =>
Enumerable.Range
(
minLength,
maxLength-minLength+1
)
.Select
(
length => stringSoFar +
(
length == 0 ? "" : prefix
+ Enumerable.Range(0, length)
.Select(i => symbol)
.Aggregate((c, n) => c + n)
)
)
);
}
}
public class Program
{
public static void Main()
{
var results = new List<string> { "" }; //Empty to start
var list = results
.AddPossibilities("h", @"" , 1, 2)
.AddPossibilities("m", @"\:" , 1, 2)
.AddPossibilities("s", @"\:" , 1, 2)
.AddPossibilities("f", @"\." , 0, 3);
var timeSpan = new TimeSpan(0,1,2,3,4);
foreach (var s in list)
{
Console.WriteLine(timeSpan.ToString(s));
}
}
}
输出:
1:2:3
1:2:3.0
1:2:3.00
1:2:3.004
1:2:03
1:2:03.0
1:2:03.00
1:2:03.004
1:02:3
1:02:3.0
1:02:3.00
1:02:3.004
1:02:03
1:02:03.0
1:02:03.00
1:02:03.004
01:2:3
01:2:3.0
01:2:3.00
01:2:3.004
01:2:03
01:2:03.0
01:2:03.00
01:2:03.004
01:02:3
01:02:3.0
01:02:3.00
01:02:3.004
01:02:03
01:02:03.0
01:02:03.00
01:02:03.004
Click here for working code 在 DotNetFiddle 上。