C#解析字符串到日期\时间

时间:2016-05-25 20:00:06

标签: c# regex datetime

对于我们的jenkins构建,我今天有以下列表,我想解析这个列表并返回构建的日期\时间。

List (Time since build) 
-----------------------
 1 day 21 hr 
 1 day 22 hr 
 1 mo 14 days
 1 mo 14 days
27 days 
 1 day 6 hr 
 1 mo 14 days
 6 min 13 sec

例如:1天21小时 - >从今天起的时间应该从05/22/2016 09:00:00 PM返回

我把以下正则表达式版本放在一起......但它感觉非常hacky和脆弱。

如何更好地解析此文本。

using System;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string txt = "1 day 21 hr";

            string regexday = "(\\d\\s+day)"; // 1 day
            string regexdaymultiple = "(\\d\\d\\s+day)"; //10 days
            string regexhr = "(\\s+\\d\\s+hr)"; // 1 hr
            string regexhrmultiple = "(\\s+\\d\\d\\s+hr)"; // 21 hr


            Regex regexdaymatch = new Regex(regexday, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match matchday = regexdaymatch.Match(txt);

            if (matchday.Success)
            {
                String d1 = matchday.Groups[1].ToString();
                DateTime now = DateTime.Now;
                Console.Write("("+now.AddDays(-Convert.ToInt32(d1.Replace(" day", "")))+")" + "\n");
            }

            Regex regexdaymutliplesmatch = new Regex(regexdaymultiple, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match matchdaymultiple = regexdaymutliplesmatch.Match(txt);

            if (matchdaymultiple.Success)
            {
                String d1 = matchdaymultiple.Groups[1].ToString();
                DateTime now = DateTime.Now;
                Console.Write("(" + now.AddDays(-Convert.ToInt32(d1.Replace(" day", ""))) + ")" + "\n");
            }

            Regex regexhrmatch = new Regex(regexhr, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match matchhr = regexhrmatch.Match(txt);

            if (matchhr.Success)
            {
                String d1 = matchhr.Groups[1].ToString();
                DateTime now = DateTime.Now;
                Console.Write("(" + now.AddHours(-Convert.ToInt32(d1.Replace(" hr", ""))) + ")" + "\n");
            }

            Regex regexhrmultiplematch = new Regex(regexhrmultiple, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match matchhrmultiple = regexhrmultiplematch.Match(txt);

            if (matchhrmultiple.Success)
            {
                String d1 = matchhrmultiple.Groups[1].ToString();
                DateTime now = DateTime.Now;
                Console.Write("(" + now.AddHours(-Convert.ToInt32(d1.Replace(" hr", ""))) + ")" + "\n");
            }

            Console.ReadLine();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

这听起来像是你解析为构建呈现的HTML并尝试向后工作。我觉得这种方法存在缺陷。我建议研究Jenkins API并以这种方式提取数据。

https://media.readthedocs.org/pdf/jenkinsapi/latest/jenkinsapi.pdf

似乎api以适当的时间戳返回数据。

答案 1 :(得分:1)

这是一个不使用Regex的课程。如果您对Regex非常熟悉,那么您的解决方案可以正常工作。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

public class TimeSinceBuildsReader
{
    public virtual IReadOnlyList<DateTime> TimesWhenBuildsOccurred(string timeSinceBuildsFilePath)
    {
        if (!File.Exists(timeSinceBuildsFilePath))
        {
            return new List<DateTime>();
        }

        var lines = File.ReadAllLines(timeSinceBuildsFilePath);
        var list = new List<DateTime>(lines.Length);
        var now = DateTime.Now;
        foreach (var line in lines)
        {
            var split = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(l => l.Trim()).ToArray();
            if (split.Length % 2 != 0)
            {
                continue;
            }

            switch (split.Length)
            {
                case 2:
                    list.Add(now.Subtract(getTimePassed(now, split[0], split[1])));
                    break;
                case 4:
                    var firstDuration = getTimePassed(now, split[0], split[1]);
                    var secondDuration = getTimePassed(now, split[2], split[3]);
                    list.Add(now.Subtract(firstDuration).Subtract(secondDuration));
                    break;
            }
        }

        return list;
    }

    private static TimeSpan getTimePassed(DateTime now, string number, string durationType)
    {
        var num = int.Parse(number);
        if (durationType.Contains("month") || durationType.Contains("mo"))
        {
            var numberOfDays = now.DayOfYear - now.AddMonths(num * -1).DayOfYear;
            return TimeSpan.FromDays(numberOfDays);
        }

        if (durationType.Contains("day"))
        {
            return TimeSpan.FromDays(num);
        }

        if (durationType.Contains("hour") || durationType.Contains("hr"))
        {
            return TimeSpan.FromHours(num);
        }

        if (durationType.Contains("minute") || durationType.Contains("min"))
        {
            return TimeSpan.FromMinutes(num);
        }

        if (durationType.Contains("second") || durationType.Contains("sec"))
        {
            return TimeSpan.FromSeconds(num);
        }

        throw new NotImplementedException("Could not parse duration type from input " + durationType);
    }
}

该方法是虚拟的,以允许例如通过例如创建该类的伪造。 FakeItEasy并作为依赖注入另一个类(如果你想扩展你的控制台应用程序)。

以下是修改后的Main方法:

private static void Main()
{
    foreach (var timestamp in new TimeSinceBuildsReader().TimesWhenBuildsOccurred("time-since-builds.txt"))
    {
        Console.WriteLine(timestamp);
    }

    Console.ReadKey();
}