使用正则表达式匹配多个更改

时间:2017-01-30 21:22:02

标签: regex powershell

正则表达将是我的死亡。我正在从企业密码管理器解析日志。这就是少数几个日志的样子:

date_time=2017-01-27 23:17:39 user=John Doe (86) ip_address=10.10.44.131 origin=web action=export password=CSDEV - SQL Account #20 (496) project=Applications (2)
date_time=2017-01-30 18:21:49 user=John Doe (86) ip_address=10.10.44.131 origin=web action=view_passwords_list additional=Active Passwords
date_time=2017-01-27 23:29:06 user=John Doe (86) ip_address=10.10.44.131 origin=web action=add_password password=Non-ACS Devices (1099) project=Infrastructure & Operations (31) additional=Import

日志中的每一行都以五个标记开头:date_time,user,ip_address,origin和action。不过,之后最多可以增加三个标签:“密码”,“项目”和“附加”。

这些额外的标签正在帮助我。我需要能够捕获所有可用的标签。现在我有:

date_time=(.+) user=(.+) ip_address=(.+) origin=(.+) action=(.+) (password=(.+)|project=(.+)|additional=(.+))+

根据regex101,这很接近,但并不完全达到目的。

https://regex101.com/r/eA2eE1/4

我的猜测是最后的飞跃与贪婪与懒惰有关,但我现在已经达到了我的正则表达式知识的目的。

感谢您提供的任何帮助!

5 个答案:

答案 0 :(得分:2)

您可以使用

^date_time=([\d-]+ [\d:]+) user=(.+?) ip_address=([\d.]+) origin=(.+?) action=(.+?)(?: password=((?:(?!\w+=).)*))?(?: project=((?:(?!\w+=).)*))?(?: additional=(.+?))?$

请参阅regex demo

<强>详情:

  • ^ - 字符串开头
  • date_time= - 文字字符序列
  • ([\d-]+ [\d:]+) - 第1组:一个或多个数字或-,空格和1位数或:
  • user= - 文字字符序列
  • (.+?) - 第2组:尽可能少的1个字符
  • ip_address= - 文字字符序列
  • ([\d.]+) - 第3组:一个或多个数字或.
  • origin= - 文字字符序列
  • (.+?) - 第4组:尽可能少的1个字符
  • action= - 文字字符序列
  • (.+?) - 第5组:尽可能少的1个字符
  • (?: password=((?:(?!\w+=).)*))? - 与以下序列匹配的可选组:
    • password= - 文字字符序列
    • ((?:(?!\w+=).)*) - tempered greedy token匹配0次或多次出现的任何字符,这些字符不是1 +字字符的起始序列,后跟=
  • (?: project=((?:(?!\w+=).)*))? - 与上述类似
  • (?: additional=(.+?))? - 与上述类似,将调和的贪婪令牌替换为.+?以匹配任何1个字符,尽可能少
  • $ - 字符串结束。

答案 1 :(得分:1)

为什么不将它拆分为键/值对?应该更容易,并且更好地适应未来的适应性。在Regex引擎上也会更容易,也更容易阅读。总是越简单越好。

(\w+=)

您可以在RextesterRegex101

上对其进行测试

答案 2 :(得分:0)

没有花哨的正则表达式,但这可行:

{'name':'something', **rest}

您的变量已准备就绪。如果不存在可选标记,则将其设置为In [13]: reshaped = [] ...: for d in my_list: ...: for k, v in d.items(): ...: new = {'name': k} ...: new.update(v) ...: reshaped.append(new) ...: In [14]: reshaped Out[14]: [{'a': '23', 'b': '15', 'c': '5', 'd': '-1', 'name': 0}, {'a': '5', 'b': '6', 'c': '7', 'd': '9', 'name': 1}, {'a': '9', 'b': '15', 'c': '5', 'd': '7', 'name': 2}, {'a': '5', 'b': '249', 'c': '92', 'd': '-4', 'name': 0}, {'a': '51', 'b': '5', 'c': '34', 'd': '1', 'name': 1}, {'a': '3', 'b': '8', 'c': '3', 'd': '11', 'name': 2}]

答案 3 :(得分:0)

好的,我将在这里采取稍微不同的方向......首先我会设置输入文字:

$Text = @"
date_time=2017-01-27 23:17:39 user=John Doe (86) ip_address=10.10.44.131 origin=web action=export password=CSDEV - SQL Account #20 (496) project=Applications (2)
date_time=2017-01-30 18:21:49 user=John Doe (86) ip_address=10.10.44.131 origin=web action=view_passwords_list additional=Active Passwords
date_time=2017-01-27 23:29:06 user=John Doe (86) ip_address=10.10.44.131 origin=web action=add_password password=Non-ACS Devices (1099) project=Infrastructure & Operations (31) additional=Import
"@ -split "[\r\n]+"|?{$_}

好的,所以现在基本上我的文字就好像我在你的文件上做了Get-Content一样。接下来,对于每一行,我们将创建一个包含每个可能属性的空白[PSCustomObject]。然后我们将每一行拆分为Something=A Value的块,然后对于在'='上拆分的每个位,并在对象上设置该属性。最后我们输出对象。

$Text |%{
$curObj = new-object psobject -Property @{
date_time=''
user=''
ip_address=''
origin=''
action='' 
password=''
project=''
additional=''
}
$_ -split "(\S+=.+?)(?=(?:\S+=|$))"|?{$_}|%{$curObj.$($_.Split('=')[0]) = $_.Split('=')[1]}
$curObj
}

从那里你可以将它传递给Export-CSV或者在数组中捕获结果,或者用它们做任何你想做的事情。我将它传送到Format-Table并得到:

date_time            origin action               ip_address    user           project                           additional       password                      
---------            ------ ------               ----------    ----           -------                           ----------       --------                      
2017-01-27 23:17:39  web    export               10.10.44.131  John Doe (86)  Applications (2)                                   CSDEV - SQL Account #20 (496) 
2017-01-30 18:21:49  web    view_passwords_list  10.10.44.131  John Doe (86)                                    Active Passwords                               
2017-01-27 23:29:06  web    add_password         10.10.44.131  John Doe (86)  Infrastructure & Operations (31)  Import           Non-ACS Devices (1099)        

答案 4 :(得分:0)

使用内置的ConvertFrom-StringData cmdlet。

$array = Get-Content -literal 'c:\data.log' |
    ForEach { $_ -replace '\s+(?=\w+=)', "`n" | ConvertFrom-StringData }

此命令输出一个哈希表数组,其中每个元素对应于日志中的一行,key = value对会自动创建为每个哈希表的属性。

注意:

  • \s+(?=\w+=)拆分意味着我们会拆分任何空格,后跟一个关键名称。
  • 如果日志文件很大,请使用[IO.StreamReader]

    $reader = [IO.StreamReader]'c:\data.log'
    $array = while (!$reader.EndOfStream) {
        $reader.ReadLine() -replace '\s+(?=\w+=)', "`n" | ConvertFrom-StringData
    }
    
  • 要输出与CSV兼容的对象,请对PSCustomObject(PowerShell 3+)或PSObject进行类型转换。