为时间跨度 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 上。