枚举和字符串匹配

jzm*_*jzm 6 c# enums

我本质上是想读取一个xml文件.其中一个值具有后缀,例如" 30d".这意味着'30天'.所以我试图将其转换为DateTime.Now.AddDays(30).要在XML中读取此字段,我决定使用枚举:

enum DurationType { Min = "m", Hours = "h", Days = "d" }
Run Code Online (Sandbox Code Playgroud)

现在我不确定如何有效地处理这个问题(当涉及枚举时我有点愚蠢).我应该首先将字符串中的后缀(在本例中为"d")分开,然后在enum使用switch语句中尝试匹配它吗?

我想如果你哑巴了我的问题,这将会是:什么是从,以获得最佳的方式30d,来DateTime.Now.AddDays(30)

sa_*_*213 6

您可以创建一个ExtensionMethod来解析字符串并返回所需的DateTime

就像是:

    public static DateTime AddDuration(this DateTime datetime, string str)
    {
        int value = 0;
        int mutiplier = str.EndsWith("d") ? 1440 : str.EndsWith("h") ?  60 : 1;
        if (int.TryParse(str.TrimEnd(new char[]{'m','h','d'}), out value))
        {
            return datetime.AddMinutes(value * mutiplier);
        }
        return datetime;
    }
Run Code Online (Sandbox Code Playgroud)

用法:

 var date = DateTime.Now.AddDuration("2d");
Run Code Online (Sandbox Code Playgroud)

  • 绝对是这里最简单的答案.我唯一想改变的是将字符串拆分为""并通过foreach循环运行它以便它可以接受像DateTime.Now.AddDuration("12d 2h 30m")这样的值; (2认同)

Dr.*_*ice 5

这似乎是使用正则表达式的好地方; 特别是捕获组.

以下是一个工作示例:

using System;
using System.Text.RegularExpressions;

namespace RegexCaptureGroups
{
    class Program
    {
        // Below is a breakdown of this regular expression:
        // First, one or more digits followed by "d" or "D" to represent days.
        // Second, one or more digits followed by "h" or "H" to represent hours.
        // Third, one or more digits followed by "m" or "M" to represent minutes.
        // Each component can be separated by any number of spaces, or none.
        private static readonly Regex DurationRegex = new Regex(@"((?<Days>\d+)d)?\s*((?<Hours>\d+)h)?\s*((?<Minutes>\d+)m)?", RegexOptions.IgnoreCase);

        public static TimeSpan ParseDuration(string input)
        {
            var match = DurationRegex.Match(input);

            var days = match.Groups["Days"].Value;
            var hours = match.Groups["Hours"].Value;
            var minutes = match.Groups["Minutes"].Value;

            int daysAsInt32, hoursAsInt32, minutesAsInt32;

            if (!int.TryParse(days, out daysAsInt32))
                daysAsInt32 = 0;

            if (!int.TryParse(hours, out hoursAsInt32))
                hoursAsInt32 = 0;

            if (!int.TryParse(minutes, out minutesAsInt32))
                minutesAsInt32 = 0;

            return new TimeSpan(daysAsInt32, hoursAsInt32, minutesAsInt32, 0);
        }

        static void Main(string[] args)
        {
            Console.WriteLine(ParseDuration("30d"));
            Console.WriteLine(ParseDuration("12h"));
            Console.WriteLine(ParseDuration("20m"));
            Console.WriteLine(ParseDuration("1d 12h"));
            Console.WriteLine(ParseDuration("5d 30m"));
            Console.WriteLine(ParseDuration("1d 12h 20m"));

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:下面是一个替代,稍微更精简的上述版本,虽然我不确定哪一个我更喜欢.我通常不喜欢过于密集的代码.我调整了正则表达式,每个数字都限制了10位数.这允许我安全地使用该int.Parse函数,因为我知道输入包含至少一个数字且最多十个(除非它根本没有捕获,在这种情况下它将是空字符串:因此,目的是ParseInt32ZeroIfNullOrEmpty方法).

        // Below is a breakdown of this regular expression:
        // First, one to ten digits followed by "d" or "D" to represent days.
        // Second, one to ten digits followed by "h" or "H" to represent hours.
        // Third, one to ten digits followed by "m" or "M" to represent minutes.
        // Each component can be separated by any number of spaces, or none.
        private static readonly Regex DurationRegex = new Regex(@"((?<Days>\d{1,10})d)?\s*((?<Hours>\d{1,10})h)?\s*((?<Minutes>\d{1,10})m)?", RegexOptions.IgnoreCase);

        private static int ParseInt32ZeroIfNullOrEmpty(string input)
        {
            return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
        }

        public static TimeSpan ParseDuration(string input)
        {
            var match = DurationRegex.Match(input);

            return new TimeSpan(
                ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
                ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
                ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
                0);
        }
Run Code Online (Sandbox Code Playgroud)

编辑:为了更进一步,我在下面添加了另一个版本,它处理日,小时,分钟,秒和毫秒,每个版本都有各种缩写.为了便于阅读,我将正则表达式拆分为多行.注意,我还必须通过(\b|(?=[^a-z]))在每个组件的末尾使用来调整表达式:这是因为"ms"单元被捕获为"m"单元.与"[^ az]"一起使用的"?="的特殊语法表示匹配字符但不"消耗"它.

    // Below is a breakdown of this regular expression:
    // First, one to ten digits followed by "d", "dy", "dys", "day", or "days".
    // Second, one to ten digits followed by "h", "hr", "hrs", "hour", or "hours".
    // Third, one to ten digits followed by "m", "min", "minute", or "minutes".
    // Fourth, one to ten digits followed by "s", "sec", "second", or "seconds".
    // Fifth, one to ten digits followed by "ms", "msec", "millisec", "millisecond", or "milliseconds".
    // Each component may be separated by any number of spaces, or none.
    // The expression is case-insensitive.
    private static readonly Regex DurationRegex = new Regex(@"
        ((?<Days>\d{1,10})(d|dy|dys|day|days)(\b|(?=[^a-z])))?\s*
        ((?<Hours>\d{1,10})(h|hr|hrs|hour|hours)(\b|(?=[^a-z])))?\s*
        ((?<Minutes>\d{1,10})(m|min|minute|minutes)(\b|(?=[^a-z])))?\s*
        ((?<Seconds>\d{1,10})(s|sec|second|seconds)(\b|(?=[^a-z])))?\s*
        ((?<Milliseconds>\d{1,10})(ms|msec|millisec|millisecond|milliseconds)(\b|(?=[^a-z])))?",
        RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

    private static int ParseInt32ZeroIfNullOrEmpty(string input)
    {
        return string.IsNullOrEmpty(input) ? 0 : int.Parse(input);
    }

    public static TimeSpan ParseDuration(string input)
    {
        var match = DurationRegex.Match(input);

        return new TimeSpan(
            ParseInt32ZeroIfNullOrEmpty(match.Groups["Days"].Value),
            ParseInt32ZeroIfNullOrEmpty(match.Groups["Hours"].Value),
            ParseInt32ZeroIfNullOrEmpty(match.Groups["Minutes"].Value),
            ParseInt32ZeroIfNullOrEmpty(match.Groups["Seconds"].Value),
            ParseInt32ZeroIfNullOrEmpty(match.Groups["Milliseconds"].Value));
    }
Run Code Online (Sandbox Code Playgroud)