C# 正则表达式拆分AmazonS3存储桶日志的列?

C# 正则表达式拆分AmazonS3存储桶日志的列?,c#,java,regex,ssis,C#,Java,Regex,Ssis,我正在为我公司的S3存储桶设置一个ETL过程,以便跟踪我们的使用情况。我在分解S3日志文件的列时遇到了一些问题,因为Amazon使用空格、双引号和方括号来分隔列 我在这篇文章中找到了这个正则表达式:[^\\s\']+\'([^\']*)\“\'([^']*)”:这让我非常接近。我只需要帮助调整它以忽略单引号,并忽略“[”和“]”之间的空格 下面是我们的一个文件中的一行示例: dd8d30dd085515d73b318a83f4946b26d49294a95030e4a7919de0ba6654c

我正在为我公司的S3存储桶设置一个ETL过程,以便跟踪我们的使用情况。我在分解S3日志文件的列时遇到了一些问题,因为Amazon使用空格、双引号和方括号来分隔列

我在这篇文章中找到了这个正则表达式:
[^\\s\']+\'([^\']*)\“\'([^']*)”
:这让我非常接近。我只需要帮助调整它以忽略单引号,并忽略“[”和“]”之间的空格

下面是我们的一个文件中的一行示例:

dd8d30dd085515d73b318a83f4946b26d49294a95030e4a7919de0ba6654c362 ourbucket.name.config [31/Oct/2011:17:00:04 +0000] 184.191.213.218 - 013259AC1A20DF37 REST.GET.OBJECT ourbucket.name.config.txt "GET /ourbucket.name.config.txt HTTP/1.1" 200 - 325 325 16 16 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6" -
以下是格式定义:

任何帮助都将不胜感激

编辑:为了响应FaileDev,输出应该是包含在两个方括号(例如[foo-bar])、两个引号(例如“foo-bar”)或空格(例如foo-bar)之间的任何字符串(其中foo和bar将分别匹配。我在下面的块中将我提供的示例行中的每个匹配都分解为它自己的行:

dd8d30dd085515d73b318a83f4946b26d49294a95030e4a7919de0ba6654c362 
ourbucket.name.config 
[31/Oct/2011:17:00:04 +0000] 
184.191.213.218 
- 
013259AC1A20DF37 
REST.GET.OBJECT 
ourbucket.name.config.txt 
"GET /ourbucket.name.config.txt HTTP/1.1" 
200 
- 
325 
325 
16 
16 
"-" 
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6" 
-

无法使用string.split执行此操作,您需要迭代“column”组的所有捕获(如果您使用的是C#)

在匹配过程中,最简单的方法是保持引号和方括号处于打开状态,然后使用Trim(“[”、“\”、“““”)将它们去掉

@“^((?[^\s\“\[\]]+\[^\]\[]+\]\\[]+\]\\“[^\”]+\”\s+$”

下面是我为解析节点中的s3日志文件而编写的哑正则表达式:

/^(.*?)\s(.*?)\s(\[.*?\])\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(\".*?\")\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(.*?)\s(\".*?\")\s(\".*?\")\s(.*?)$/

正如我所说,这是“愚蠢的”-它严重依赖于它们不改变日志格式,并且每个字段不包含任何奇怪的字符。

这是一个python解决方案,可能会帮助某些人。它还为您删除引号和方括号:

import re
log = '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be mybucket [06/Feb/2014:00:00:38 +0000] 192.0.2.3 79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be A1206F460EXAMPLE REST.GET.BUCKETPOLICY - "GET /mybucket?policy HTTP/1.1" 404 NoSuchBucketPolicy 297 - 38 - "-" "S3Console/0.4" -'

regex = '(?:"([^"]+)")|(?:\[([^\]]+)\])|([^ ]+)'

# Result is a list of triples, with only one having a value
# (due to the three group types: '""' or '[]' or '')
result = re.compile(regex).findall(log)
for a, b, c in result:
    print(a or b or c)
输出:

79A59DF900B949E55D96A1E698FBACEDF6E09D98EACF8D5218E7CD47EF2BE
我的桶
2014年2月6日:00:00:38+0000
192.0.2.3
79A59DF900B949E55D96A1E698FBACED6E09D98EACF8D5218E7CD47EF2BE
A1206F460示例
REST.GET.bucket策略
-
获取/mybucket?策略HTTP/1.1
404
无此政策
297
-
38
-
-
S30/0.4
-
jon@jon-笔记本电脑:~/Downloads$python regex.py
79A59DF900B949E55D96A1E698FBACED6E09D98EACF8D5218E7CD47EF2BE
我的桶
2014年2月6日:00:00:38+0000
192.0.2.3
79A59DF900B949E55D96A1E698FBACED6E09D98EACF8D5218E7CD47EF2BE
A1206F460示例
REST.GET.bucket策略
-
获取/mybucket?策略HTTP/1.1
404
无此政策
297
-
38
-
-
S30/0.4
-

我同意@andy!考虑到S3的访问日志已经存在了多长时间,我真不敢相信有更多的人不处理S3的访问日志


这是我使用的regexp

/(?:([a-z0-9]+)|-) (?:([a-z0-9\.-_]+)|-) (?:\[([^\]]+)\]|-) (?:([0-9\.]+)|-) (?:([a-z0-9]+)|-) (?:([a-z0-9.-_]+)|-) (?:([a-z\.]+)|-) (?:([a-z0-9\.-_\/]+)|-) (?:"-"|"([^"]+)"|-) (?:(\d+)|-) (?:([a-z]+)|-) (?:(\d+)|-) (?:(\d+)|-) (?:(\d+)|-) (?:(\d+)|-) (?:"-"|"([^"]+)"|-) (?:"-"|"([^"]+)"|-) (?:([a-z0-9]+)|-)/i
如果您使用的是node.js,您可以利用我的模块使其更易于处理,或者将其移植到C#,基本思想都在这里

我尝试在C#中使用此选项,但发现上面的答案中有一些不正确的字符,您必须在结尾处为非引号、非括号字段使用正则表达式,否则它会匹配所有内容(使用):

第一个带括号字段、第二个带引号字段和最后一个不带引号、不带括号字段的完整正则表达式:

一个简单的C#实现:

    MatchCollection matches = Regex.Matches(contents, @"(\[[^\]\[]+\])|(""[^""]+"")|([^\s""\[\]]+)");
    for (int i = 0; i < matches.Count; i++)
    {
        Console.WriteLine(i + ": " + matches[i].ToString().Trim('[', ']', '"'));
    }
MatchCollection matches=Regex.matches(内容,@“(\[^\]\[]+\]))|(“[^”“]+”)|([^\s”“\[\]+]);
for(int i=0;i
这是我从中复制的正则表达式,并对其进行了一些修改,使其在ASP.NET核心中工作

new Regex("([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)");
如果有人想用c#class来存储访问日志,下面是解析日志文件每一行并为其创建
S3ServerAccessLog
对象的代码

private List<S3ServerAccessLog> ParseLogs(string accessLogs)
{
    // split log file per new line since each log will be on a single line.
    var splittedLogs = accessLogs.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
    var parsedLogs = new List<S3ServerAccessLog>();

    foreach (var logLine in splittedLogs)
    {
        var parsedLog = ACCESS_LOG_REGEX.Split(logLine).Where(s => s.Length > 0).ToList();
                
        // construct 
        var logModel = new S3ServerAccessLog
        {
            BucketOwner = parsedLog[0],
            BucketName = parsedLog[1],
            RequestDateTime = DateTimeOffset.ParseExact(parsedLog[2], "dd/MMM/yyyy:HH:mm:ss K", CultureInfo.InvariantCulture),
            RemoteIP = parsedLog[3],
            Requester = parsedLog[4],
            RequestId = parsedLog[5],
            Operation = parsedLog[6],
            Key = parsedLog[7],
            RequestUri = parsedLog[8].Replace("\"", ""),
            HttpStatus = int.Parse(parsedLog[9]),
            ErrorCode = parsedLog[10],
            BytesSent = parsedLog[11],
            ObjectSize = parsedLog[12],
            TotalTime = parsedLog[13],
            TurnAroundTime = parsedLog[14],
            Referrer = parsedLog[15].Replace("\"", ""),
            UserAgent = parsedLog[16].Replace("\"", ""),
            VersionId = parsedLog[17],
            HostId = parsedLog[18],
            Sigv = parsedLog[19],
            CipherSuite = parsedLog[20],
            AuthType = parsedLog[21],
            EndPoint = parsedLog[22],
            TlsVersion = parsedLog[23]
        };

        parsedLogs.Add(logModel);
    }

    return parsedLogs;
}
私有列表解析日志(字符串访问日志)
{
//每新行拆分日志文件,因为每个日志将位于一行上。
var splittedLogs=accessLogs.Split(“\r\n”,StringSplitOptions.RemoveEmptyEntries);
var parsedLogs=新列表();
foreach(拆分日志中的变量logLine)
{
var parsedLog=ACCESS_LOG_REGEX.Split(logLine).Where(s=>s.Length>0.ToList();
//构造
var logModel=新的S3ServerAccessLog
{
BucketOwner=parsedLog[0],
BucketName=parsedLog[1],
RequestDateTime=DateTimeOffset.ParseExact(parsedLog[2],“dd/MMM/yyyy:HH:mm:ss K”,CultureInfo.InvariantCulture),
RemoteIP=parsedLog[3],
请求者=parsedLog[4],
RequestId=parsedLog[5],
操作=解析日志[6],
Key=parsedLog[7],
RequestUri=parsedLog[8]。替换(“\”,“),
HttpStatus=int.Parse(parsedLog[9]),
ErrorCode=parsedLog[10],
BytesSent=parsedLog[11],
ObjectSize=parsedLog[12],
TotalTime=parsedLog[13],
周转时间=解析日志[14],
referer=parsedLog[15]。替换(“\”,“),
UserAgent=parsedLog[16]。替换(“\”,“),
VersionId=parsedLog[17],
HostId=parsedLog[18],
Sigv=parsedLog[19],
CipherSuite=parsedLog[20],
AuthType=parsedLog[21],
EndPoint=parsedLog[22],
TlsVersion=parsedLog[23]
};
添加(logModel);
}
返回解析日志;
}

输出到底应该是什么?我不敢相信更多的人不需要这些信息!好问题,谢谢!谢谢,ORing模式工作得很好。这个字符串模式最适合C:@([^\s\”“[]+)|([[^][]+])|(\[^\\]+\)(\[^\]+\)“谢谢。堆栈溢出似乎删除了我的斜杠……我忘了将其嵌入代码块。现在更新。”。
new Regex("([^ ]*) ([^ ]*) \\[(.*?)\\] ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) (-|[0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) (\"[^\"]*\"|-) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)");
private List<S3ServerAccessLog> ParseLogs(string accessLogs)
{
    // split log file per new line since each log will be on a single line.
    var splittedLogs = accessLogs.Split("\r\n", StringSplitOptions.RemoveEmptyEntries);
    var parsedLogs = new List<S3ServerAccessLog>();

    foreach (var logLine in splittedLogs)
    {
        var parsedLog = ACCESS_LOG_REGEX.Split(logLine).Where(s => s.Length > 0).ToList();
                
        // construct 
        var logModel = new S3ServerAccessLog
        {
            BucketOwner = parsedLog[0],
            BucketName = parsedLog[1],
            RequestDateTime = DateTimeOffset.ParseExact(parsedLog[2], "dd/MMM/yyyy:HH:mm:ss K", CultureInfo.InvariantCulture),
            RemoteIP = parsedLog[3],
            Requester = parsedLog[4],
            RequestId = parsedLog[5],
            Operation = parsedLog[6],
            Key = parsedLog[7],
            RequestUri = parsedLog[8].Replace("\"", ""),
            HttpStatus = int.Parse(parsedLog[9]),
            ErrorCode = parsedLog[10],
            BytesSent = parsedLog[11],
            ObjectSize = parsedLog[12],
            TotalTime = parsedLog[13],
            TurnAroundTime = parsedLog[14],
            Referrer = parsedLog[15].Replace("\"", ""),
            UserAgent = parsedLog[16].Replace("\"", ""),
            VersionId = parsedLog[17],
            HostId = parsedLog[18],
            Sigv = parsedLog[19],
            CipherSuite = parsedLog[20],
            AuthType = parsedLog[21],
            EndPoint = parsedLog[22],
            TlsVersion = parsedLog[23]
        };

        parsedLogs.Add(logModel);
    }

    return parsedLogs;
}