现在有一行行的文本数据( DNS 日志),是非结构化的,但是也有结构,比如
ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1 这种
如何提取出指定字段的行呢? 比如过滤出 rcode=ok 的字段行,或者如何将这些数据变成结构化的,比如对应到一个 表格里,如果有的话 就为 “=” 后面的值,如果没有就为空
1
matsuz 2019-04-07 16:29:50 +08:00
正则表达式
|
2
lastpass 2019-04-07 16:30:57 +08:00 via Android
py 不知道。
antlr 倒是非常简单。 |
3
anonymoustian OP @matsuz 谢谢老哥,除了正则还有什么方便的库么
|
4
zjsxwc 2019-04-07 16:35:11 +08:00
C 语言可以 sscanf
Python 可以 正则 |
5
recall704 2019-04-07 16:37:10 +08:00
如果只是这种,不是可以按空格分割吗?
|
6
anonymoustian OP @recall704 是可以按照空格分割,但是比如说我想提 src=232.190.252.222 后面的 ip 地址,我在想有没有这种方法可以直接 getline('src') 这种 好像也不麻烦哈~ 而且字段不一定存在
|
7
matsuz 2019-04-07 16:44:34 +08:00 1
@lastpass 你这种结构的最合适的就是正则
```python import re match = re.match( r'ad=([^ ]+)\W+cd=([^ ]+)\W+rcode=([^ ]+)\W+qdcount=([^ ]+)\W+ancount=([^ ]+)\W+nscount=([^ ]+)\W+arcount=([^ ]+)\W+src=([^ ]+)\W+dst=([^ ]+)', 'ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1', ) for i in range(1, 10): print(match.group(i)) ``` |
8
e2c 2019-04-07 16:47:10 +08:00
这么简单的文本,可以自己解析了
|
9
CEBBCAT 2019-04-07 16:58:17 +08:00 via Android 2
为什么我想到的是两个 spilt ?我思维太初级了?
|
10
Kilerd 2019-04-07 17:07:15 +08:00 via iPhone
这么简单的处理都写不出来吗?
|
11
Kylin30 2019-04-07 17:17:28 +08:00
要我这外行来搞的话,那就直接先 split 空格然后 split 等号,2 个循环就变成了一个 dict,之后处理就很随便了。每行格式固定的话,不计较什么性能代码好看的还是非常简单的。
希望有大佬来说说,看看有什么高级搞法学习一下。 |
12
westoy 2019-04-07 17:19:07 +08:00
from collections import defaultdict
import re ini = defaultdict(lambda: None, re.findall('(?:^|\s+)([^\=]+)\=([\S]+)','''ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1''')) print(ini['helloworld'], ini['src']) 如果结构复杂一点, 比如 xx=xx xx="yy" xx='yy' xx='zz abc'这种, 用 pyparsing 更方便一点 |
13
Levox 2019-04-07 18:24:06 +08:00 1
``` python
>>> s = 'ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1' >>> >>> from urllib import parse >>> d = parse.parse_qs(s.replace(' ', '&')) >>> >>> d['src'] ['232.190.252.222'] >>> ``` |
15
911speedstar 2019-04-07 22:19:54 +08:00
非结构化用正则,结构化用 xpath。。。
|
16
mintist 2019-04-07 22:43:37 +08:00
先 split,然后用个 json 来结构化存储
|
17
lastpass 2019-04-08 00:34:47 +08:00 via Android
@matsuz 不不不,正则并没有 antlr 强大。而且正则那又臭又长辣眼睛的代码无论是写还是维护都是灾难。所以,我目前项目里处理这种字符串都是使用的 antlr。
|
18
jiaqiangbandongg 2019-04-08 04:04:34 +08:00
s = "ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1"
data = dict(map(lambda x:x.split("="),str.split())) print(data["rcode"]) |
19
jiaqiangbandongg 2019-04-08 04:05:23 +08:00
一行处理就够了
|
20
dartabe 2019-04-08 06:03:45 +08:00
split 之后存个字典 再查找键值就行了 求大佬评价一下。。。
|
21
LokiSharp 2019-04-08 09:09:56 +08:00
用 pyparsing 定义语法之后解析
|
22
yuhr123 2019-04-08 09:14:12 +08:00 via iPhone
split 生成以空格分割的列表,迭代列表查找=号所在位置,用这个位置坐切片取封号前面的字符串,和你需要的字符串做 if 判断。
|
23
niknik 2019-04-08 09:56:16 +08:00
以空格 split 啊,然后转 json
|
24
shuax 2019-04-08 10:09:33 +08:00
直接两次 split 多简单啊
|
25
capric 2019-04-08 10:21:08 +08:00
src = 'ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1'
dst = dict(parts.split('=') for parts in src.split()) print(dst.get('ad')) |
26
thautwarm 2019-04-08 11:00:18 +08:00 via Android
除开正则还有各种文法库。
比如我写的一个库的话, import rbnf.zero as ze ze_exp = ze.compile(""" import std.common.[Number Name Space] Pair ::= keys=Name '::=' values=(~Space)* -> (k.value, "".join(x.value for x in v)) Row ::= pairs=Pair+ -> dict(pairs) Logs ::= (rows<<Row '\n'+)+ -> rows """ ze_exp.match("你的日志字符串").result |
27
www5070504 2019-04-08 11:24:11 +08:00
两个 split 加上 字典推导式 用默认字典可以避免键可能不存在的情况
|
28
btv2bt 2019-04-08 11:49:52 +08:00
应该可以直接转 dict 吧
|
30
TheBestSivir 2019-04-08 15:39:20 +08:00
看你的场景咯。你对性能有需求么?有的话还是不要正则了。另外,这种简单场景正则真的有利于维护么???
|
31
hakono 2019-04-08 16:11:46 +08:00 via Android
噗,其实说真的,如果要搜索的字符串格式固定的话,首先想到的不应该是转为 dict,而是
for line in log_lines: if "rcode=ok" in line: xxxxxxxxxxxxxxxxxxx |
32
caryqy 2019-04-08 16:15:38 +08:00
cat dns.log | awk -F ' ' '{print $3}' >> res.log
|
33
caryqy 2019-04-08 16:19:59 +08:00
cat dns.log | awk -F ' ' '{if ($3=="rcode=ok") {print $3} else {print "rcode=error"}}'
|
34
omph 2019-04-08 16:25:38 +08:00
http://pypi.python.org/pypi/parse
类似于 C 语言的 sscanf 字符串扫描 |
35
bumz 2019-04-08 17:20:15 +08:00
用 BNF 写一下文法?然后用 BNF Parser Generator 生成一下相应的解析器
(其实这种正则就行,逃 (再复杂直接用递归下降写就好 |
36
freakxx 2019-04-08 17:48:43 +08:00
content = "ad=0 cd=0 rcode=ok qdcount=1 ancount=0 nscount=0 arcount=1 src=232.190.252.222 dst=45.80.170.1 test test2"
1 直接字符串判断 rocde_is_ok = "rcode=ok" rocde_is_ok in content 2 pairs = content.split(' ') content_dict = {} for name_value in pairs: nv = name_value.split('=', 1) if len(nv) != 2: nv.append("") key, value = nv content_dict[key] = value |
37
saulshao 2019-04-08 23:46:08 +08:00
上来就先 Split,然后写个函数分析 split 之后的结果,决定要不要将每个=加入最终结果。
我不建议用正则,你这个规律性太强了...... |
38
lastpass 2019-04-09 00:54:40 +08:00 via Android
@C0dEr 我看的就是 The Definitive ANTLR 4 Reference 这本书。简单易懂\(//∇//)\。
|
39
wonderay 2019-04-09 13:27:17 +08:00
|
40
shawndev 2019-04-11 16:52:54 +08:00
空格换成换行就是 ini 格式了。
|
41
shawndev 2019-04-11 16:53:43 +08:00
空格换成&,前面随便添加一个 baseUrl,用现成的 url 解析库解析。
|