正则表达将是我的死亡。我正在从企业密码管理器解析日志。这就是少数几个日志的样子:
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
我的猜测是最后的飞跃与贪婪与懒惰有关,但我现在已经达到了我的正则表达式知识的目的。
感谢您提供的任何帮助!
答案 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+=)
上对其进行测试
答案 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进行类型转换。