命理的条文在古书里面都是pdf,要自己一个个手敲,还好有了网络很多工作有人已经做了。但是直接复制下来没有什么作用,因为一条断语往往包含了多条规则,有的还包含了几个方面的断言,这个时候就使用到爬虫+正则表达式来处理了。这里用到了一个在线验证正则的网站https://regex101.com/1 提取中间字段
下面代码中(?<=(:))
是匹配:
开头的字符串,而(?=(生人))
则匹配以生人
为结尾的字符串
def parse_content(content):
month = re.search(r'(?<=(:)).*(?=(生人))',content).group()
print(month)
if __name__ == '__main__':
# parse_txt('file1.txt')
parse_content('生月论命:正月生人')
# 输出结果为:正月
2 中间存在回车的文本
看到下面的\n是没有问题的,但是如果是回车键,却又问题
因为.
是匹配除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r]。,而[\s\S]
是匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。故这里少做一些调整就可以了。
month = re.search(r'(?<=(二、生月对时论六亲))[\s\S]*(?=(三、月上十神论))',content).group()
另外一种解决方案是re.S
,这样就支持换行符的匹配了
content = re.search(r'(?<=(二、生月对时论六亲)).*(?=(三、月上十神论))',content,re.S).group()
3 正则提取字符串
内容如下,按照行进行解析,分为四段
正月:子时。兄弟排行、四。五岁体弱、父母双全。(大运忌午)
正月:丑时。兄弟排行二、五。十岁体弱,父先亡。(大运忌未)
正月:寅时。兄弟排行曰、六(性孤辞,爱好艺卫。(大运忌申)
正月:卯时。兄弟排行一、四。母先亡。(大运忌酉)
正月:辰时。兄弟徘行一一、五。二岁体弱、父母双全。(大运忌戌)
正月:巳时。二十岁以前有一大难,有养父母者为佳。(大运忌亥)
正月:午时。为人好礼仪,女性好修饰。(大运忌子)
正月:未时。女命婚姻多吵架,男命不受祖产,独自成功。(大运忌丑)
正月:申时。夜多啼哭,幼儿之时不好带(大运忌寅)
正月:酉时。无兄弟、多姊妹。得父母荫蔽。(大运忌卯)
正月:戌时。手足感情不佳、父先亡。(大运忌辰)
正月:亥时。智慧开早、幼时了了、中年平平、晚年发达、母先亡。(大运忌巳)
先看正则表达式([\u4e00-\u9fa5]{1,2})月:([\u4e00-\u9fa5]{1})时。(?<=时。)(.*)(?=。()
从下方这种下发,会将符合正则的情况,写入到group中,注意将你想要匹配的内容正则增加上括号,因为()
是用来分组的
如果?<=
、?=
这两个匹配之后和匹配之前的,就不需要加上括号,运行就是下面的结果
分取四段完整的正则是([\u4e00-\u9fa5]{1,2})月:([\u4e00-\u9fa5]{1})时。(?<=时。)(.*)(?=。()。((.*))
这个表达式还是有些绕,可以改成([\u4e00-\u9fa5]{1,2})月:([\u4e00-\u9fa5]{1})时。(.*)((.*))
,因为分割符较为清晰,采取的方式也想对比较容易,然后根据group的序号进行取值即可
当然group需要并不是很好,如果有key、value的方式取值,可读岂不是更好,故而采取下面的模式进行处理。
assertion = '正月:午时。为人好礼仪,女性好修饰。(大运忌子)'
reg = re.compile(r'(?P<month>[\u4e00-\u9fa5]+)月:(?P<hour>[\u4e00-\u9fa5]{1})时。(?P<assertion>.*)((?P<dayun>.*))')
regm = reg.match(assertion)
linebits = regm.groupdict()
for k,v in linebits.items():
print(k,v)
4 使用断言
大运里面的内容网站可能有错别字,那么这个时候需要用正则做一下筛选
取正确的内容,可以有很多种方式
使用.*(?:忌[子丑寅卯辰巳午未申酉戌亥])$
,这里使用(?:pattern)
,他并不捕获分组
.*忌[子丑寅卯辰巳午未申酉戌亥]$
、
.*忌(?:[子丑寅卯辰巳午未申酉戌亥])$
大运(?=忌[子丑寅卯辰巳午未申酉戌亥]$)
这几种方式均可。
上面是筛选出正确的内容,如果想找到不符合的内容,使用的表达式如下,将正向匹配取反,大运(?!忌[子丑寅卯辰巳午未申酉戌亥]$)
,意思就是不以忌[子丑寅卯辰巳午未申酉戌亥]$
结尾的内容
# 换行
mgs = re.split(r'\n',content)
# 去除空行
mgs = list(filter(None,mgs))
#
for mg in mgs:
# 获取月份、时辰、断语
# 获取大运
pass
5 匹配符合规则的字符串
以八字开头和结尾,取其中,注意这里要用re.S
因为做了换行
import re
import csv
try:
file = open('../files/千里.txt','r',encoding='UTF-8')
data = file.read()
# pattern = r'(?<=(([甲乙丙丁庚戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]{2}){4}))(.*?)(?=(([甲乙丙丁庚戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]{2}){4}))'
# pattern = r'甲子(.*?)甲子'
pattern = r'(?<=(([甲乙丙丁庚戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]{2}){4}))(.*?)(?=(([甲乙丙丁庚戊己庚辛壬癸子丑寅卯辰巳午未申酉戌亥]{2}){4}))'
dg = re.findall(pattern, data,re.S)
c_file = open('../files/千里.csv','a+',encoding='UTF-8',newline='')
c_writer = csv.writer(c_file)
for d in dg:
ba = d[0]
content = d[2].lstrip()
year = ba[0:2]
month = ba[2:4]
day = ba[4:6]
hour = ba[6:]
bazi = '{} {} {} {}'.format(year,month,day,hour)
c_writer.writerow([year,month,day,hour,bazi,content])
finally:
if file:
file.close()
if c_file:
c_file.close()
结果还是要稍作处理,并不是直接使用,但已经比我复制粘贴快多了
6 去掉一些特殊字符串
def remove_xa0(value):
'''
\xa0 是不间断空白符
'''
return value.replace(u'\xa0',u'')
去掉'A型 [128]'
中符合[128]
条件的内容,用正则怎么写呢?re.sub的使用方法
a = '赵頔麦 [40] 、麦子、麦麦、今麦'
def test_01(a):
p = re.compile('\[[\d\]]+')
print(p.sub("",a))
7 js的一些正则样例
7.1 去空格\s
标识匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。并不算复杂,只要肯学
/**
* 去掉右侧空格
* @param {*} s
*/
function rtrim(s){
return s.replace(/(\s*$)/g, "");
}
7.2 提取给定的字符串
有一次跟C++的原函数对接,我只需要传递sql语句进去,返回的结果是{ "": "2"}
,没有key值,没法转成json,怎么取这个2呢,截取字符串?也很简单
let cn = result.match(/\d+/)[0]
return parseInt(cn)