当前位置: 首页 > 科技观察

再见,正则表达式

时间:2023-03-20 12:41:40 科技观察

从指定的字符串中获取期望的数据。正常人都会想到正则表达式吧?写过正则表达式的人都知道,正则表达式并不难上手,也很容易写。简单的。但是正则表达式几乎没有可读性。维护起来真是让人抓狂。不要因为你写了这个正则表达式就认为你可以控制它。一个月后你可能不知道。可谓天下苦难久矣。今天给大家介绍一个好东西,可以让你免于经常性的噩梦,那就是Python中一个非常冷门的库——parse。一、真实案例以最近使用parse的一个真实案例为例。下面是ovs的流表。现在我需要在一个虚拟机(网口)中收集并提取出有多少流量和多少数据包流过这个流表。即每个in_port对应的n_bytes和n_packets的值。cookie=0x9816da8e872d717d,duration=298506.364s,table=0,n_packets=480,n_bytes=20160,priority=10,ip,in_port="tapbbdf080b-c2"actions=NORMAL如果是你,你会怎么做?开头用逗号隔开,然后用等号隔开得到值?大家可以试试看,写出来的代码应该和我想象的一样,没有一丝美感。让我告诉你我是怎么做到的?可以看到,我使用了一个叫parse的第三方包,需要自己安装。$python-mpipinstallparse从上面的案例中,你应该能感受到parse的重要性,Parsingcanonicalstrings非常强大。2.parse的结果parse的结果只有两个结果:如果没有匹配,parse的值为None>>>parse("halo","hello")isNoneTrue>>>如果有匹配,parse的值是Result实例>>>parse("hello","helloworld")>>>parse("hello","hello")>>>>如果你写一个解析规则没有为字段定义字段名,它是一个匿名字段,Result将是一个类似于列表的实例,演示如下:>>>profile=parse("Iam{},{}yearsold,{}","IamJack,27yearsold,male")>>>profile>>>profile[0]'Jack'>>>profile[1]'27'>>>profile[2]'male'如果你写的解析规则为字段定义了字段名,Result会是一个类似字典的实例,演示如下:>>>profile=parse("Iam{name},{age}yearsold,{gender}","IamJack,27yearsold,male")>>>profile>>>profile['name']'Jack'>>>profile['age']'27'>>>profile['gender']'male'3.重用pattern与使用re一样,parse也支持模式重复使用>>>fromparseimportcompile>>>>>>pattern=compile("Iam{},{}yearsold,{}")>>>pattern.parse("IamJack,27yearsold,male")>>>>>>>pattern.parse("IamTom,26yearsold,male")4.typeConversion从上面的例子,你应该能注意到parse得到age的时候,变成了“27”。这是一个字符串。有没有办法根据我们的类型提取出来?转换呢?你可以这样写。>>>fromparseimportparse>>>profile=parse("Iam{name},{age:d}yearsold,{gender}","IamJack,27yearsold,male")>>>profile>>>type(profile["age"])除了转成整数,还有没有其他的format?有很多内置格式,比如匹配时间>>>parse('Meetat{:tg}','Meetat1/2/201111:00PM')更多类型请参考官方文档:TypeCharactersMatchedOutputlLetters(ASCII)strwLetters,numbersandunderscorestrWNotletters,numbersandunderscorestrWNotletters,numbersandunderscorestrsWhitespacestrSNon-whitespacestrd数字(有效地tegernumbers)intD非数字strn带千位分隔符(,或.)的数字int%百分比(转换为value/100.0)floatf定点数floatF十进制数Decimale带指数的浮点数,例如1.1e-10,NAN(不区分大小写)floatg一般数字格式(d、f或e)floatb二进制数into八进制数intx十六进制数(小写和大写)inttiISO8601格式化日期/时间,例如1972-01-20T10:21:36Z(“T”和“Z”可选)日期时间teRFC2822电子邮件格式日期/时间,例如Mon,20Jan197210:21:36+1000datetimetg全局(日/月)格式日期/时间例如20/1/197210:21:36AM+1:00datetimetaUS(月/日)格式日期/时间,例如1/20/197210:21:36PM+10:30datetimetcctime()格式化日期/时间,例如SunSep1601:03:521973datetimethHTTP日志格式日期/时间,例如21/Nov/2011:00:07:11+0000datetimetsLinux系统日志格式日期/时间例如11月9日03:37:44datetimett时间例如10:21:36PM-5:30time5.提取时间去除空格去除两边空格>>>解析('你好{},hellopython','helloworld,hellopython')<结果('世界',){}>>>>>>>>>>>解析('你好{:^},hellopython','helloworld,hellopython')去掉左边的空格>>>parse('hello{:>},hellopython','helloworld,hellopython')去掉右边的空格>>>parse('hello{:<},hellopython','helloworld,hellopython')6.Case-sensitiveswitchParse默认是case-sensitiveInsensitive,你写hello和HELLO是一样的如果需要区分大小写,可以加一个参数,如下所示:>>>parse('SPAM','spam')>>>parse('SPAM','spam')isNoneFalse>>>parse('SPAM','spam',case_sensitive=True)isNoneTrue7.匹配字符数精确匹配:指定最大字符数>>>parse('{:.2}{:.2}','hello')#字符数不匹配>>>>>>parse('{:.2}{:.2}','hell')#匹配的字符数模糊匹配:指定最小字符数>>>parse('{:.2}{:2}','hello')>>>>>>parse('{:2}{:2}','hello')如果要在精确/模糊匹配模式下进行格式转换,可以这样写>>>parse('{:2}{:2}','1024')<结果('10','24'){}>>>>>>>>>>>解析('{:2d}{:2d}','1024')<结果(10,24){}>8。三个重要的属性Parsefixed中有三个非常重要的属性:一个由位置提取的匿名字段的元组named:一个包含命名字段的字典span:存储匹配字段的位置,male")>>>profile.fixed('male',)>>>profile.named{'age':27,'name':'Jack'}>>>profile.spans{0:(25,29),'年龄':(11,13),'姓名':(5,9)}>>>9.自定义类型转换匹配到的字符串,将作为参数传递给相应的函数。比如我们之前说的,将字符串转为整数>>>parse("Iam{:d}","Iam27")>>>type(_[0])>>>相当于>>>defmyint(string):...returnint(string)...>>>>>>>>>>parse("Iam{:myint}","Iam27",dict(myint=myint))>>>type(_[0])>>>使用它,我们可以自定义很多功能,比如我想把匹配字符串全部大写>>>defshouty(string):...returnstring.upper()...>>>parse('{:shouty}world','helloworld',dict(shouty=shouty))>>>10总结parse库在字符串解析和处理场景中提供的便利,在一些肉眼可见且易于使用的场景中简单的场景,使用parse可以比使用re写正则表达式的效率高出几个层次。用它写的代码美观可读,后期维护代码也没有压力。建议您使用它。本文转载自微信公众号《Python编程时间》,可通过以下二维码关注。转载本文请联系Python编程时间公众号。