现在有一行行的文本数据( 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 的字段行,或者如何将这些数据变成结构化的,比如对应到一个 表格里,如果有的话 就为 “=” 后面的值,如果没有就为空
现在有一行行的文本数据( 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 的字段行,或者如何将这些数据变成结构化的,比如对应到一个 表格里,如果有的话 就为 “=” 后面的值,如果没有就为空
|
matsuzApr 7, 2019
1
正则表达式
|
|
lastpassApr 7, 2019 via Android
2
py 不知道。
antlr 倒是非常简单。 |
|
3
@matsuz 谢谢老哥,除了正则还有什么方便的库么
|
|
zjsxwcApr 7, 2019
4
C 语言可以 sscanf
Python 可以 正则 |
|
recall704Apr 7, 2019
5
如果只是这种,不是可以按空格分割吗?
|
|
6
@recall704 是可以按照空格分割,但是比如说我想提 src=232.190.252.222 后面的 ip 地址,我在想有没有这种方法可以直接 getline('src') 这种 好像也不麻烦哈~ 而且字段不一定存在
|
|
7
@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)) ``` |
|
e2cApr 7, 2019
8
这么简单的文本,可以自己解析了
|
|
9
为什么我想到的是两个 spilt ?我思维太初级了?
|
|
KilerdApr 7, 2019 via iPhone
10
这么简单的处理都写不出来吗?
|
|
Kylin30Apr 7, 2019
11
要我这外行来搞的话,那就直接先 split 空格然后 split 等号,2 个循环就变成了一个 dict,之后处理就很随便了。每行格式固定的话,不计较什么性能代码好看的还是非常简单的。
希望有大佬来说说,看看有什么高级搞法学习一下。 |
|
westoyApr 7, 2019
12
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
``` 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'] >>> ``` |
|
911speedstarApr 7, 2019
15
非结构化用正则,结构化用 xpath。。。
|
|
mintistApr 7, 2019
16
先 split,然后用个 json 来结构化存储
|
|
lastpassApr 8, 2019 via Android
17
@matsuz 不不不,正则并没有 antlr 强大。而且正则那又臭又长辣眼睛的代码无论是写还是维护都是灾难。所以,我目前项目里处理这种字符串都是使用的 antlr。
|
|
jiaqiangbandonggApr 8, 2019
18
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"]) |
|
jiaqiangbandonggApr 8, 2019
19
一行处理就够了
|
|
dartabeApr 8, 2019
20
split 之后存个字典 再查找键值就行了 求大佬评价一下。。。
|
|
LokiSharpApr 8, 2019
21
用 pyparsing 定义语法之后解析
|
|
yuhr123Apr 8, 2019 via iPhone
22
split 生成以空格分割的列表,迭代列表查找=号所在位置,用这个位置坐切片取封号前面的字符串,和你需要的字符串做 if 判断。
|
|
niknikApr 8, 2019
23
以空格 split 啊,然后转 json
|
|
momo1999Apr 8, 2019
24
直接两次 split 多简单啊
|
|
capricApr 8, 2019
25
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')) |
|
thautwarmApr 8, 2019 via Android
26
除开正则还有各种文法库。
比如我写的一个库的话, 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 |
|
www5070504Apr 8, 2019
27
两个 split 加上 字典推导式 用默认字典可以避免键可能不存在的情况
|
|
btv2btApr 8, 2019
28
应该可以直接转 dict 吧
|
|
z67nnciQnb7r8bLfApr 8, 2019
29
@lastpass 最近在搞 antlr,有啥好的资料看看吗
|
|
TheBestSivirApr 8, 2019
30
看你的场景咯。你对性能有需求么?有的话还是不要正则了。另外,这种简单场景正则真的有利于维护么???
|
|
hakonoApr 8, 2019 via Android
31
噗,其实说真的,如果要搜索的字符串格式固定的话,首先想到的不应该是转为 dict,而是
for line in log_lines: if "rcode=ok" in line: xxxxxxxxxxxxxxxxxxx |
|
caryqyApr 8, 2019
32
cat dns.log | awk -F ' ' '{print $3}' >> res.log
|
|
caryqyApr 8, 2019
33
cat dns.log | awk -F ' ' '{if ($3=="rcode=ok") {print $3} else {print "rcode=error"}}'
|
|
omphApr 8, 2019
34
http://pypi.python.org/pypi/parse
类似于 C 语言的 sscanf 字符串扫描 |
|
bumzApr 8, 2019
35
用 BNF 写一下文法?然后用 BNF Parser Generator 生成一下相应的解析器
(其实这种正则就行,逃 (再复杂直接用递归下降写就好 |
|
metamaskApr 8, 2019
36
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 |
|
saulshaoApr 8, 2019
37
上来就先 Split,然后写个函数分析 split 之后的结果,决定要不要将每个=加入最终结果。
我不建议用正则,你这个规律性太强了...... |
|
wonderayApr 9, 2019
39
|
|
shawndevApr 11, 2019
40
空格换成换行就是 ini 格式了。
|
|
shawndevApr 11, 2019
41
空格换成&,前面随便添加一个 baseUrl,用现成的 url 解析库解析。
|