1

搜索了一下,但我只发现用逗号分隔的情况。本案不同。

为了解释我的问题,我将展示一个小例子:

JAN 01 00:00:01 <Admin> Action, May have spaces etc.

(这是一个日志条目)

我想将此字符串解析为几个变量。第一位显然是日期,没有年份。在 <> 之间列出了登录名,在日志条目后面。

配置应该是这样的:

{month} {day} {hour}:{minute}:{second} <{login}> {the_rest}

这将允许更改而无需对整个内容进行硬编码(使用拆分等)。

我认为在这里使用正则表达式可能很有用,但我对它并不太了解,也不知道它是否可以在这种情况下使用。速度并不重要,但我真的不知道如何实现这一点。

谢谢,

~Tgys

4

6 回答 6

3
string line = "JAN 01 00:00:01 <Admin> Action, May have spaces etc.";
var m = Regex.Match(line, @"(\w{3} \d{2} \d{2}:\d{2}:\d{2}) \<(\w+)\>([\w ]+),([\w ]+)");

var date = DateTime.ParseExact(m.Groups[1].Value,"MMM dd HH:mm:ss",CultureInfo.InvariantCulture);
var user = m.Groups[2].Value;
var action = m.Groups[3].Value;
var text = m.Groups[4].Value;
于 2012-06-20T10:30:25.000 回答
1

您仍然可以使用 split ,在空格字符上进行拆分。

显然,您的问题是您希望在一定数量的拆分后保留空格,以便您的“其余部分”保持在一起。

split 的可选 int 参数允许您提供希望执行的最大拆分数量,因此可能会提供您正在寻找的解决方法。

http://msdn.microsoft.com/en-us/library/c1bs0eda.aspx

于 2012-06-20T10:28:38.980 回答
1

您还可以将其用作正则表达式并使用捕获的组:

^(?<Month>\w{3})\s(?<Day>\d{2})\s(?<Hour>\d{2}):(?<Min>\d{2}):(?<Sec>\d{2})\s(?<User>\<(\w.+?)\>)(.+)$

RegEx Hero 示例在这里

编辑:错过了用户部分。

于 2012-06-20T10:37:47.607 回答
1

正则表达式确实是这里的正确工具。首先,让我们看看如何使用硬编码的正则表达式来解析此日志。

使用硬编码的正则表达式进行解析

var str = "JAN 01 00:00:01 <Admin> Action, May have spaces etc.";
var re = new Regex("^" +
       @"(?<month>(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))" +
       " " +
       @"(?<day>\d+)" +
       " " +
       @"(?<hour>\d+)" +
       ":" +
       @"(?<the_rest>.*)" +
       "$");
var match = re.Match(str);

我们在这里所做的是使用命名捕获组逐段创建正则表达式。为简洁起见,我没有捕获所有相关信息,也没有花太多时间考虑在每个组的上下文中什么是有效输入(例如daywill match 999,尽管那不是有效的一天)。这一切都可以在以后发生;现在,看看它的实际效果

从预定义的部分构造正则表达式

下一步是很好地将每个捕获组的定义提取到字典中:

var groups = new Dictionary<string, string>
{
    { "month", "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)" },
    { "day", @"\d+" },
    { "hour", @"\d+" },
    { "the_rest", ".*" },
};

鉴于此,我们现在可以构造相同的正则表达式

var re = new Regex("^" +
       string.Format("(?<month{0}>)", groups["month"]) +
       " " +
       string.Format("(?<day{0}>)", groups["day"]) +
       " " +
       string.Format("(?<hour{0}>)", groups["hour"]) +
       ":" +
       string.Format("(?<the_rest{0}>)", groups["the_rest"]) +
       "$");

好的,这开始看起来像是可以动态构建的东西。

根据用户提供的规范构造正则表达式

假设我们想从一个看起来像的规范构建它

"{month} {day} {hour}:{the_rest}"

这该怎么做?用另一个正则表达式!具体来说,我们将使用 that 的重载Regex.Replace,可以用函数的结果替换匹配项:

var format = "{month} {day} {hour}:{the_rest}";
var result = Regex.Replace(format, @"\{(\w+)\}", m => groups[m.Groups[1].Value]);

回来之前看看这个。

使用正则表达式解析输入

此时,我们可以传入一个格式规范,并根据该格式取回一个匹配输入的正则表达式。还剩下什么?要将正则表达式与输入匹配的结果转换回“动态”结构:

var format = "{month} {day} {hour}:{the_rest}";
var re = Regex.Replace(format,
                       @"\{(\w+)\}",
                       m => string.Format("(?<{0}>{1})", m.Groups[1].Value, groups[m.Groups[1].Value]));
var regex = new Regex("^" + re + "$", RegexOptions.ExplicitCapture);
var match = regex.Match(str);

拉出最终结果

在此刻:

  • 我们可以测试match.Success一下动态构造的表达式是否与输入匹配
  • 我们可以迭代regex.GetGroupNames()以获取解析中使用的组的名称
  • 我们可以迭代match.Groups得到解析每个组的结果

所以让我们把它们放在字典里:

var results = regex.GetGroupNames().ToDictionary(n => n, n => match.Groups[n].Value);

成功!

您现在可以创建一个Parse允许这样做的方法:

var input = "JAN 01 00:00:01 <Admin> Action, May have spaces etc.";
var format = "{month} {day} {hour}:{the_rest}";
var results = Parse(input, format);

Parse将识别(但不允许用户修改)表达式,例如"{month}",同时允许用户自由混合和匹配这些表达式以解析输入。

查看最终结果

于 2012-06-20T10:45:26.227 回答
0

您可以使用此正则表达式:

(?<Month>[A-Z]{3})\s(?<Day>[0-9]{1,2})\s(?<Hour>[0-9]{1,2}):(?<Minute>[0-9]{1,2}):(?<Second>[0-9]{1,2})\s<(?<Login>[^>]+)>(?<Rest>.*)

这有点笨拙和复杂,但我希望下面的例子能让你得到你想要的。

class Foo
{
public string Month { get; set; }
public int Day { get; set; }
public int Hour { get; set; }
public int Minute { get; set; }
public int Second { get; set; }
public string Login { get; set; }
public string Rest { get; set; }
}

string strRegex = @"(?<Month>[A-Z]{3})\s(?<Day>[0-9]{1,2})\s(?<Hour>[0-9]{1,2}):(?<Minute>[0-9]{1,2}):(?<Second>[0-9]{1,2})\s<(?<Login>[^>]+)>(?<Rest>.*)";
RegexOptions myRegexOptions = RegexOptions.None;
Regex myRegex = new Regex(strRegex, myRegexOptions);
string strTargetString = @"JAN 01 00:00:01 <Admin> Action, May have spaces etc. \n";

foreach (Match myMatch in myRegex.Matches(strTargetString))
{
    if (myMatch.Success)
    {
        new Foo
        {
            Month = myMatch.Groups["Month"].Value,
            Day = Convert.ToInt32(myMatch.Groups["Day"].Value),
            Hour = Convert.ToInt32(myMatch.Groups["Hour"].Value),
            Minute = Convert.ToInt32(myMatch.Groups["Minute"].Value),
            Second = Convert.ToInt32(myMatch.Groups["Second"].Value),
            Login = myMatch.Groups["Login"].Value,
            Rest = myMatch.Groups["Rest"].Value
        }
    }
}
于 2012-06-20T10:38:24.043 回答
0

下面的正则表达式可以解决问题。

^([A-Z]{3})\s*([0-9]{1,2})\s*([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})\s*<(.+)>\s*(.+)

使用在线正则表达式生成器对其进行了测试。

它将返回 7 个捕获的组。

  • 第 1 组:([AZ]{3}):月
  • 第 2 组:([0-9]{1,2}):天
  • 第 3 组:([0-9]{1,2}):小时
  • 第 4 组:([0-9]{1,2}):分钟
  • 第 5 组:([0-9]{1,2}):第二
  • 第 6 组:(.+):用户名
  • 第 7 组:(.+):其余
于 2012-06-20T10:41:00.420 回答