从 12 个月布尔值列表创建日期范围字符串

本文关键字:创建日期 范围 字符串 列表 布尔值 | 更新日期: 2023-09-27 18:22:02

我有一个包含 12 个布尔属性的 c# 类;

可用一月,可用二月,可用三月,4月可用...等

此类的每个实例都可以将任意数量的实例作为 true,并且通常它们按顺序运行。 即 AvailableFeb - AvailableApr 将是真的,但不是其他的。有时只有一个布尔值为真,即仅在一个月内可用。有时它们都是,即全年可用。

有时,这是棘手的一点,它们将有两个范围,即 2 月至 4 月和 8 月至 10 月可用。

我正在尝试编写一个函数来返回一个字符串来表示所做的选择。

仅选择了 1 个布尔值,我想返回(例如(:"仅限 2 月"。

选择的范围(例如(:"1 月至 3 月"。

多个范围(例如(:"1 月至 3 月,8 月至 11 月"。

混合单曲和范围(例如(:"1 月至 3 月,9 月"。

全部选择:"全年"。

范围是连续月份被分配为真的地方,例如 1 月、2 月、3 月为真应导致 1 月至 3 月。

尝试使用带有简单条件检查的循环,但它很混乱,我无法正确处理,我很后悔将它们存储为单个属性而不是 int 数组,但现在我被困住了。我想知道是否有办法使用反射然后循环将布尔值存储在另一个属性中。到目前为止还没有运气。任何帮助非常感谢!

谢谢

从 12 个月布尔值列表创建日期范围字符串

如果你想稍微改变你的类,那就按照这个方式去做!.

您可以有 12 个属性并将它们映射到单个 int 数组中。所以你有长度为 12 的 int 数组。当intArray[0] = 1表示第一个月可用时。如果intArray[0] = 0则表示第一个月不可用,依此类推。

您将此 int 数组转换为字符串,每个月以 1 为基数表示的基于 1 的索引,但如果它不可用,则改为输入 0。后来我们使用字典通过给出月份的数字来获取月份的名称。

示例 1:

"003456000a00"

这意味着几个月3th,4th,5th,6tha = 10th可用。 然后使用正则表达式来解析它并找到匹配项。正则表达式模式将[^0]+ .表示它匹配除 0 以外的任何字符。

所以正则表达式会给我们这个匹配。

Match 1 : 3456
Match 2 : a

第一场比赛长度超过 1 意味着它是一个月份的范围。 所以我们取第一个字符和最后一个字符。 我们加入他们与-.在这里,它将36.所以匹配 1 应该变成

Mar-Jun

第二场比赛长度只有1这意味着它是一个月。所以它应该成为

Oct

由于我们有两场比赛,我们将这些与,连接起来,最后输出是Mar-Jun , Oct

示例 2:

"020000000000"

比赛

Match 1 : 2

由于我们只有 1 个匹配项,并且匹配长度为 1,这应该变成

Feb Only

例3:

"023456780000"

比赛

Match 1 : 234567
这只是一场比赛

,但这场比赛的长度不止一场比赛。 所以我们只是拿27,然后加入他们-.

Feb-Jul

例4:

"123456789abc"

比赛

Match 1 : 123456789abc

正如你在这里看到的,我们有所有的月份。 这场比赛的长度是 12 所以应该是

Year round

例5:

"123456000abc"

比赛

Match 1 : 123456
Match 2 : abc

在这里,我们有两场比赛。 它可以是Jan-Jun , Oct-Dec但更好的表示(如您在评论中提到的(是 Oct-Jun .那应该是abc123456.因此,我们检查最后一场比赛是否以c结束,第一场比赛以1开始,然后我们加入第一场比赛的最后一场比赛。

Oct-Jun

法典:

如您所见,它将变得简单。

internal class AvailableYear
{
    private readonly int[] _available;
    private static readonly Regex MatchTrue = new Regex("[^0]+");
    private static readonly Dictionary<string, string> GetName = new Dictionary<string, string>
    {
        {"1","Jan" },
        {"2","Feb" },
        {"3","Mar" },
        {"4","Apr" },
        {"5","May" },
        {"6","Jun" },
        {"7","Jul" },
        {"8","Aug" },
        {"9","Sep" },
        {"a","Oct" },
        {"b","Nov" },
        {"c","Dec" },
    };
    public AvailableYear(params int[] available)
    {
        if (available.Length > 12) throw new IndexOutOfRangeException("given parameters should not exceed 12 months.");
        _available = available;
    }
    public int AvaialableJan
    {
        get { return _available[0]; }
        set { _available[0] = value; }
    }
    public int AvailableFeb
    {
        get { return _available[1]; }
        set { _available[1] = value; }
    }
    public int AvailableMar
    {
        get { return _available[2]; }
        set { _available[2] = value; }
    }
    public int AvailableApr
    {
        get { return _available[3]; }
        set { _available[3] = value; }
    }
    public int AvaialableMay
    {
        get { return _available[4]; }
        set { _available[4] = value; }
    }
    public int AvaialableJun
    {
        get { return _available[5]; }
        set { _available[5] = value; }
    }
    public int AvaialableJul
    {
        get { return _available[6]; }
        set { _available[6] = value; }
    }
    public int AvaialableAug
    {
        get { return _available[7]; }
        set { _available[7] = value; }
    }
    public int AvaialableSep
    {
        get { return _available[8]; }
        set { _available[8] = value; }
    }
    public int AvaialableOct
    {
        get { return _available[9]; }
        set { _available[9] = value; }
    }
    public int AvaialableNov
    {
        get { return _available[10]; }
        set { _available[10] = value; }
    }
    public int AvaialableDec
    {
        get { return _available[11]; }
        set { _available[11] = value; }
    }
    public override string ToString()
    {
        string values = string.Join("", _available.Select((x, i) => x == 0 ? "0" : Convert.ToString(i + 1, 16)));
        var matches = MatchTrue.Matches(values).Cast<Match>().Select(x => x.Value).ToList();
        if (matches.Count == 0)
        {
            return "None";
        }
        if (matches[0].Length == 12)
        {
            return "Year round";
        }
        if (matches.Count == 1 && matches[0].Length == 1)
        {
            return GetName[matches[0]] + " Only";
        }
        else
        {
            if (matches.First().StartsWith("1") && matches.Last().EndsWith("c"))
            {
                matches[0] = matches.Last() + matches.First();
                matches.RemoveAt(matches.Count - 1);
            }
            List<string> output = new List<string>();
            foreach (var match in matches)
            {
                if (match.Length == 1)
                {
                    output.Add(GetName[match]);
                }
                else
                {
                    output.Add(GetName[match.First().ToString()] + "-" +
                               GetName[match.Last().ToString()]);
                }
            }
            return string.Join(", ", output);
        }
    }
}

这是测试。

static void Main()
{
    AvailableYear ay = new AvailableYear(1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0);
    Console.WriteLine(ay.ToString());
    // Output : Jan , Apr-Jul , Nov
}

更新:

如果要在构造函数中分配布尔值,可以将构造函数更改为此值。

public AvailableYear(params bool[] available)
{
    if (available.Length > 12) throw new IndexOutOfRangeException("given parameters should not exceed 12 months.");
    _available = available.Select(Convert.ToInt32).ToArray();
}

并像这样创建实例。 无需每次都编写 Convert.ToInt32。

return new AvailableYear(AvailableJan, AvailableFeb, AvailableMar...., AvailableDec).ToString();

你可以在没有像这样反射的情况下做到这一点:

string FormatMonths(MyClass myObject)
{
    return FormatMonths(
        myObject.AvailableJan,
        myObject.AvailableFeb,
        myObject.AvailableMar,
        myObject.AvailableApr,
        myObject.AvailableMay,
        myObject.AvailableJun,
        myObject.AvailableJul,
        myObject.AvailableAug,
        myObject.AvailableSep,
        myObject.AvailableOct,
        myObject.AvailableNov,
        myObject.AvailableDec);
}

private static string[] months = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
string FormatMonthRange(int startMonth, int endMonth, StringBuilder sb)
{
    if (startMonth == 0 && endMonth == 11)
        sb.Append("Year round");
    else if (endMonth == 11 && sb[0] == 'J' && sb[1] == 'a')
    {
        // this deals with wrap around from December to January:
        if (sb.Length > 3 && sb[3] == '-')
            sb.Remove(0, 4);
        sb.Insert(0, months[startMonth] + "-");
    }
    else
    {
        if (sb.Length > 0)
            sb.Append(", ");
        sb.Append(months[startMonth]);
        if (startMonth != endMonth)
            sb.Append("-").Append(months[endMonth]);
    }
}
string FormatMonths(params bool[] monthBools)
{
    var sb = new StringBuilder();
    int rangeStart = -1;
    for (int i = 0; i < monthBools.Length; i++)
    {
        if (monthBools[i])
        {
            if (rangeStart < 0)
                rangeStart = i;
        }
        else
        {
            if (rangeStart >= 0)
            {
                FormatMonthRange(rangeStart, i - 1, sb);
            }
            rangeStart = -1;
        }
    }
    if (rangeStart >= 0)
        FormatMonthRange(rangeStart, monthBools.Length - 1, sb);
    if (sb.Length == 3)
        sb.Append(" only");
    return sb.ToString();
}

因为你不能像这样简单地迭代成员,所以你可以创建一些属性来检测那些布尔模因,方法是使用属性中的订单号。例如

class Year
{
    [Month(0)]
    public bool AvaialableJan { // ... }
    [Month(1)]
    public bool AvaialableFeb { // ... }
}

然后您可以通过列表中的反射并搜索序列来获取它们。看一看:反射 - 获取属性的属性名称和值

但是更好的解决方案是在没有反射和一种ranges的情况下工作:

public class Month
{
    public string Name { //... }
}
public class Range
{
    public List<Month> Months //...
}
public class Year
{
    public List<Range> Ranges //...
}

但这两种解决方案都应该有效。