电子病例re正则解析与Python连接Sql Server 或Oracle数据库

电子病例re正则解析与Python连接Sql Server 或Oracle数据库

一:Sql Server 及Oracle连接配置:

1:Oracle连接配置即app.cof配置文件书写:

因区域平台电子病例解析采用的是Oracle连接,不管是原始数据库还是解析后的存储数据库均为Oracle数据库,因为需要配置相应的Oracle连接。即配置Oracle数据库的IP,实例,用户,密码等等。

如下:oracleDb_get为区域平台电子病例来源地址相应配置。

[oracleDb_get]                        
host = ***********                    #服务器IP
port = 1521                           #数据库端口号
user = ********                       #用户
password = ********************       #密码
dbname = ******                       #实例

如下:oracleDb_save为区域平台电子病例解析后存储地址相应配置。

[oracleDb_save]
host = ***********
port = 1521
user = ********
password = ********************
dbname = ******

2:Sql Server连接配置:

因互联互通平台电子病例解析采用的是Sql Server连接,不管是原始数据库还是解析后的存储数据库均为Sql Server数据库,因为需要配置相应的Sql Server连接。即配置Sql Server数据库的IP,实例,用户,密码等等。

如下:Db_get为人民医院互联互通平台电子病例来源地址相应配置。

[Db_get]
host = ************                 #服务器IP
port = 1433                         #数据库端口号
user = ***********                  #用户
password = **********               #密码
dbname = *******                    #实例

如下:Db_save为人民医院互联互通平台电子病例解析后存储地址相应配置。

[db_save]
host = ************
port = 1433
user = ***********
password = **********
dbname = *******

二:Python连接Sql Server 或Oracle数据库读写信息:

1:获取Sql Server 或Oracle数据库的URL地址

def get_db_url():
    '''
    获取sql server数据库的实例,用户,密码,端口号,功能:获取取数用户
    :return:
    '''
    cf = ConfigParser()
    cf.read('D:/PytionDate/emrStruct4/conf/app.conf')#app.conf文件存放路径

    dbHost = cf.get("db_get", "host")
    dbPort = cf.get("db_get", "port")
    dbUser = cf.get("db_get", "user")
    dbPassword = cf.get("db_get", "password")
    dbName = cf.get("db_get", "dbName")
    db_url = "mssql+pymssql://"+dbUser+":"+dbPassword+"@"+dbHost+":"+dbPort+"/"+dbName
    return  db_url
   
    
def get_db_url2():
    '''
    获取oracle数据库的实例,用户,密码,端口号,功能:获取取数用户
    :return:
    '''
    cf = ConfigParser()
    # cf.read(sys.path[0] + "/conf/app.conf")
    cf.read('D:/PytionDate/emrStruct4/conf/app.conf')

    dbHost = cf.get("oracleDb_get", "host")
    dbPort = cf.get("oracleDb_get", "port")
    dbUser = cf.get("oracleDb_get", "user")
    dbPassword = cf.get("oracleDb_get", "password")
    dbName = cf.get("oracleDb_get", "dbName")
    db_url = dbUser + "/" + dbPassword + "@" + dbHost + ":" + dbPort + "/" + dbName
    return  db_url

2:Python连接Sql Server数据库

conn = create_engine(
            get_db_url()       #调用上述的def get_db_url()函数获取Sql Server的URL地址
    		, max_overflow=0,  # 超过连接池大小外最多创建的连接数
    		pool_size=5,  # 连接池大小
    		pool_timeout=30,  # 连接池中没有线程最多等待时间,否则报错
    		pool_recycle=-1  # 多久之后对连接池中的连接进行回收(重置)-1不回收
    		, echo=True
    		, encoding='utf-8'
    		, convert_unicode=True
)


# 每次执行数据库操作的时候,都需要创建一个session,相当于管理器(相当于Django的ORM的objects)
session_factory = sessionmaker(bind=conn)
# 线程安全,基于本地线程实现每个线程用同一个session
Session = scoped_session(session_factory)
# 实例化(相当于实现了一个单例模式)
session = Session()

Base = declarative_base()
# declarative_base()是一个工厂函数,它为声明性类定义构造基类。init 在继承了Base。隶属sqlalchemy模块之下

3:Python连接Oracle数据库

url_get = get_db_url2()
#调用上述的def get_db_url2()函数获取Oracler的URL地址
db = oracle.connect(url_get)
#python连接Oracler数据库

4:Python从Sql Server数据库中获取信息(取数)

#编写sql语句从原始数据库中查询出所需数据(注意:需求不同,sql语句也不同)
sql = "select y.KSSJ, m.BRID, m.MZHM, m.BRXM, m.jtdh lxdh, w.JLXH jlxh, w.BRTGJC DLNR, 			'' BLBH, w.JZXH jzxh from  bshrp.dbo.MS_BRDA m \
            inner join  bshrp.dbo.YS_MZ_JZLS y on y.brbh=m.brid \
            inner join  bshrp.dbo.OMR_BLZY w on w.jzxh=y.jzxh \
            where M.ZXBZ<>1  \
            and (w.BRTGJC like '%℃%' or w.BRTGJC like '%度%' or w.BRTGJC like '%T%' or\ 				w.BRTGJC like '%°%' or w.BRTGJC like '%mmHg%' \
            or w.BRTGJC like '%分%' or w.BRTGJC like '%次%' or w.BRTGJC like '%P%' or \				w.BRTGJC like '%R%'  or w.BRTGJC like '%p%' or w.BRTGJC like '%r%') \
            and y.KSSJ >= to_date('{0}', 'yyyy-MM-dd hh24:mi:ss') and y.KSSJ < \						to_date('{1}', 'yyyy-MM-dd hh24:mi:ss') \
         	order by y.KSSJ , w.JLXH ".format(str(d1), str(d2))

sj = session.execute(sql).fetchall()
#调用上述步骤2的session对象连接sql server库,即主功能:mysql查

5:Python从Oracle数据库中获取信息(取数)

#编写sql语句从原始数据库中查询出所需数据(注意:需求不同,sql语句也不同)
sql_bj = "select y.KSSJ, m.BRID, m.MZHM, m.BRXM, m.jtdh lxdh, w.JLXH jlxh, w.BRTGJC DLNR, 					  '' BLBH, w.JZXH jzxh from  his_bj_hc.MS_BRDA m \
    	            inner join  his_bj_hc.YS_MZ_JZLS y on y.brbh=m.brid \
    	            inner join  his_bj_hc.OMR_BLZY w on w.jzxh=y.jzxh \
    	            where M.ZXBZ<>1  \
    			    and (w.BRTGJC like '%℃%' or w.BRTGJC like '%度%' or w.BRTGJC like 						'%T%' or w.BRTGJC like '%°%' or w.BRTGJC like '%mmHg%' \
    			    or w.BRTGJC like '%分%' or w.BRTGJC like '%次%' or w.BRTGJC like '%P%' 					or w.BRTGJC like '%R%'  or w.BRTGJC like '%p%' or w.BRTGJC like '%r%') 
                    and y.KSSJ>=to_date('{0}','yyyy-MM-dd hh24:mi:ss') and 									y.KSSJ<to_date('{1}','yyyy-MM-dd hh24:mi:ss') \
    			 	order by y.KSSJ , w.JLXH ".format(str(d1), str(d2))

cursor = db.cursor()
#调用上述步骤3的db变量,连接Oracle数据库并创建游标
sj_bj = cursor.execute(sql_bj).fetchall()
# 连接oracle,主功能:查

6:Python连接Oracle或Sql Serve数据库创建表格

注意:无论是Python连接Oracle创建数据表格还是连接Sql Serve数据库创建数据表格,方法是一模一样的。

import time
from sqlalchemy import create_engine, ForeignKey, UniqueConstraint, Index
from sqlalchemy import Column, Integer, String, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.orm import relationship
# sqlalchemy:将类和对象转换成SQL,然后使用数据API执行SQL并获取执行结果。与pymssql结合使用,功能可创建			表,删除表,不能修改表
import pymssql
from bs4 import BeautifulSoup
# BeautifulSoup最主要的功能是从网页抓取数据。提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。
# 它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
# 自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,
# 这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
import re
import schedule, time
# 使用Schedule做Python任务调度
# 在工作中多少都会涉及到一些定时任务,比如定时邮件提醒等。
import datetime
import time

Base = declarative_base()


# declarative_base()是一个工厂函数,它为声明性类定义构造基类。init 在继承了Base。隶属sqlalchemy模块#之下功能可创建表,删除表,但不能修改表

# 查房记录
class Cfjl(Base):
    '''
    创建表格Cfjl,共22个表格,所有表格字段一模一样
    '''
    __tablename__ = 'T_Cfjl'
    ID = Column(Integer, primary_key=True)
    Zyh = Column(String(50))
    Lsh = Column(String(50))
    Title = Column(String(50))
    NR = Column(Text)
    YW = Column(Text)
    BLBH = Column(String(50))
    TJSJ = Column(String(50))

6:Python将解析数据插入Sql Serve数据库中的表格

将上述步骤4利用sql查询所得的字段一个一个调出来,注意sql server查询返回的数据类型是一组对象,而oracle查询,返回的结果是一个个列表。

for res in sj:
    #sql server查询返回的数据类型是一组对象,字段调用方式如下
    zyh = res.BRBH
    lsh = res.JZHM
    blbh = res.BLBH
    cysj = str(res.CYRQ)
    lxnr = str(res.NR).encode('latin-1').decode('gbk', 'ignore')
    jdxjsj = ''

    r1 = Qrmyy_Config.Cfjl(Zyh=zyh, Lsh=lsh, Title='查房日期时间', NR=str(jdxjsj), YW=lxnr, BLBH=blbh, TJSJ=cysj)
    #相当于sql server中的insert into数据插入sql语句,其中Qrmyy_Config.Cfjl点名指向步骤5的表格Cfjl
    session.add(r1)
    session.commit()
    session1.close()
    #sql server数据入库入表库功能:解析好的数据入库。

7:Python将解析数据插入Oracle数据库中的表格

将上述步骤5利用sql查询所得的字段一个一个调出来,注意sql server查询返回的数据类型是一组对象,而此处为oracle查询,返回的结果是一个个列表。

for res_bj in sj_bj:
	#sj_bj是sql查询返回的列表
    zyh = res_bj[8]
    lsh = res_bj[0]
    blbh = res_bj[6]
    cysj = res_bj[3]
    lxnr = res_bj[4]
    jdxjsj = res_bj[5]
    
    r1_bj = "INSERT INTO Cfjl (ID,Brid,Mzh,jzxh,BLBH,Lsh,wd) \  		   		   		VALUES({0},'{1}','{2}','{3}','{4}','{5}','{6}','{7}')".\
format('BJ_EY_MZBL_SEQ_ID.nextval', str(zyh), str(lsh), str(blbh), str(cysj),\ 	         str(lxnr), str(jdxjsj))
    #相当于Oracler中的insert into数据插入sql语句,其中Cfjl点名指向步骤5的表格Cfjl
    cursor1.execute(r1_bj)
    db.commit()
    #Oracler数据入库入表库功能:解析好的数据入库。
    cursor1.close()#关闭游标
	conn.close()#关闭数据连接

三:正则表达式

1.定义
即文本的高级匹配模式,提供搜索,替换等功能。其本质是由一 系列字符和特殊符号构成的字串,这个字串即正则表达式。

2.原理
通过普通字符和有特定含义 的字符,来组成字符串,用以描述一 定的字符串规则,比如:重复,位置等,来表达某类特定的字符串,进而匹配。

元字符使用

普通字符

匹配规则:每个普通字符匹配其对应的字符

In : re.findall('ab',"abcdefabcd")
Out: ['ab', 'ab'] 因为目标 字符串有两处 ab.

注意事项:正则表达式在 python 中也可以匹配中文

或关系

元字符: |

匹配规则: 匹配 | 两侧任意的正则表达式即可

In : re.findall('com|cn',"www.baidu.com/www.tmooc.cn")
Out: ['com', 'cn']
匹配单个字符

元字符: .

匹配规则:匹配除换行外的任意一 个字符,其中.可以代替任意字符.

In : re.findall('张.丰',"张三丰,张四丰,张五丰,张无忌")
Out: ['张三丰', '张四丰', '张五丰']
匹配字符集

元字符: [字符集]

匹配规则: 匹配字符集 中的任意一个字符

表达形式:

[abc#!好] 表示 [] 中的任意一个字符
[0-9],[a-z],[A-Z] #表示区间内的任意一 个字符
[_#?0-9a-z] 混合书写,一般区间表达写在后面
In : re.findall('[aeiou]',"How are you!")
Out: ['o', 'a', 'e', 'o', 'u']
In [32]: re.findall('[A-Z]','Tom is not Jame')
Out[32]: ['T', 'J']
匹配字符集 反集
元字符:[^字符集]

匹配规则:匹配除了字符集以外的任意一 个字符

In : re.findall('[^0-9]',"Use 007 port")
Out: ['U', 's', 'e', ' ', ' ', 'p', 'o', 'r', 't'] #中间为空字符
匹配字符串开始位置

元字符: ^

匹配规则:匹配目标 字符串的开头位置

In : re.findall('^Jame',"Jame,hello")
Out: ['Jame']
匹配字符串的结束位置

元字符: $

匹配规则: 匹配目标 字符串的结尾位置

In : re.findall('Jame$',"Hi,Jame")
Out: ['Jame']

规则技巧: ^ 和 $必然出现在正则表达式的开头和结尾处。如果两者同时出现,则中间的部分必须匹配整个目标 字符串的全部内容。

匹配开头结尾位置

元字符: \A \Z

匹配规则: \A 表示开头位置 ,\Z 表示结尾位置

In [40]: re.findall('\A\w+\Z','Jame')
Out[40]: ['Jame'] 
 #因为\w匹配普通字符,前后空字符被\A\Z匹配到了,加上连接+就是整个了.
匹配字符重复

元字符: *

匹配规则:匹配前面的字符出现 0次或多次

In : re.findall('wo*',"wooooo~~w!")
Out: ['wooooo', 'w']
In [33]: re.findall('[a-z]*','Tom is not Jam')
Out[33]: ['', 'om', '', 'is', '', 'not', '', '', 'am', '']
In [34]: re.findall('[A-Z][a-z]*','Tom is Jam')
Out[34]: ['Tom', 'Jam']

元字符:+

匹配规则: 匹配前面的字符出现 1次或多次

In : re.findall('[A-Z][a-z]+',"Hello World hello world Hello World")
Out: ['Hello', 'World', 'Hello', 'World']")

元字符:?

匹配规则: 匹配前面的字符出现 0次或 1 次

e.g. 匹配整数
In [28]: re.findall('-?[0-9]+',"Jame,age:18, -26")
Out[28]: ['18', '-26']
In [37]: re.findall('-?[0-9]',"Jame,age:18, -26")
Out[37]: ['1', '8', '-2', '6']
In [12]: re.findall('-?[0-9]+','2019?redown-15')
Out[12]: ['2019', '-15']
In [36]: re.findall('wo?','wooooo--w')
Out[36]: ['wo', 'w']

元字符:{ n}

匹配规则: 匹配前面的字符出现 n次

e.g. 匹配手机号码:因为手机号码都是 11位的,且第一 位为 1,后面 十个在 0-9中任意取.
In : re.findall('1[0-9]{n} 10}',"Jame:13886495728")
Out: ['13886495728']

元字符:{ m,n}

匹配规则: 匹配前面的字符出现 m-n次

e.g. 匹配 qq号,因为 qq都是 10,前五个在 1-9中任意取一 个,5个在 0-9 中任意取一 个
In : re.findall('[1-9][0-9]{n} 5,10}',"Baron:1259296994")
Out: ['1259296994']
匹配任意(非)数字字符

元字符: \d \D

匹配规则:\d 匹配任意数字字符,\D 匹配任意非数字字符

e.g. 匹配端口
In : re.findall('\d{1,5}',"Mysql: 3306, http:80")
Out: ['3306', '80']
In [38]: re.findall('\D{1,5}',"Mysql: 3306, http:80")
Out[38]: ['Mysql', ': ', ', htt', 'p:']
匹配任意(非)普通字符

元字符: \w \W

匹配规则: \w 匹配普通字符,\W 匹配非普通字符

说明: 普通字符指数字,字母,下划线,汉字 。

e.g. 注意'+'连接作用.
In : re.findall('\w+',"server_port = 8888")
Out: ['server_port', '8888']
In [17]: re.findall('\W+','server_port=8888')
Out[17]: ['=']
匹配任意(非)空字符

元字符: \s \S

匹配规则: \s 匹配空字符,\S 匹配非空字符

说明: 空字符指 空格 \r \n \t \v \f 字符

In : re.findall('\w+\s+\w+',"hello world")
Out: ['hello world']
In [19]: re.findall('\S+','hello world')
Out[19]: ['hello', 'world']
In [39]: re.findall('\s+','hello world')
Out[39]: [' ']
匹配(非)单词的边界位置

元字符: \b \B

匹配规则: \b 表示单词边界,\B 表示非单词边界

说明:单词边界指数字字母(汉字)下划线与其他字符的交界位置 。

In : re.findall(r'bis\b',"This is a test.")
Out: ['is'] 因为 is去前后两端.
In [21]: re.findall('is','this is a test')
Out[21]: ['is', 'is'] 因为有两个 is.

电子病例re正则解析与Python连接Sql Server 或Oracle数据库_第1张图片

正则表达式 的转义

1.如果使用正则表达式匹配特殊字符则需要加 \ 表示 转义 。
特殊字符: . * + ? ^ $ [] () {} | \

e.g. 匹配特殊字符 . 时使用 \d. 表示 本身含义
In [41]: re.findall('-?\d+\.?\d+','12 34 -1 1.56 -3.5')
Out[41]: ['12', '34', '1.56', '-3.5']
In [42]: re.findall('-?\d+\.?\d*','12 34 -1 1.56 -3.5')
Out[42]: ['12', '34', '-1', '1.56', '-3.5']
In [24]: re.findall('\$\d+','count:$100')
Out[24]: ['$100']
In [28]: re.findall('\\$\\d+','count:$100')
Out[28]: ['$100']
In [25]: re.findall('$\d+','count:$100')
Out[25]: []

2.在编程语言中,常使用原生字符串 书写正则表达式避免多重转义 的麻烦。

python 字符串 --> 正则 --> 目标 字符串
"\\$\\d+" 解析为 \$\d+ 匹配 "$100"
"\\$\\d+" 等同于 r"\$\d+"

贪婪模式 和非贪婪模式

1.定义
贪婪模式: 默认情况下,匹配重复的元字符总是尽可能多的向后匹配内容。比如: * + ? {n} m,n}
非贪婪模式(懒惰模式): 让匹配重复的元字符尽可能少的向后匹配内容。

2.贪婪模式转换为非贪婪模式

在匹配重复元字符后加 ‘?’ 号即可

*		: 		*?
+		: 		+?
? 		: 		??
{m,n} 	: 		{m,n}?
In : re.findall(r'\(.+?\)',"(abcd)efgh(higk)")
Out: ['(abcd)', '(higk)']

正则表达式 分组

1.定义
在正则表达式中,以()建立正则表达式的内部分组,子组是正则表达式的一 部分,可以作为内部整体操作对象。

2.作用

可以被作为整体操作,改变元字符的操作对象

e.g. 改变 + 号 重复的对象
In : re.search(r'(ab)+',"ababababab").group()
Out: 'ababababab'
e.g. 改变 | 号 操作对象
In : re.search(r'(王|李)\d \D w{n} 1,3}',"王者荣耀").group()
Out: '王者荣耀'

可以通过编程语言某些接口 获取匹配内容中,子组对应的内容部分

e.g. 获取 url 协议类型
In : e.search(r'(https|http|ftp|file)://\d \D S+',"https://www.baidu.com").group(1)
Out: https

3.捕获组
可以给正则表达式的子组起一 个名字,表达该子组的意义 。这种有名称的子组即为捕获组。
格式:(?Ppattern)

e.g. 给子组命名为 "pig"
In : re.search(r'(?Pab)+',"ababababab").group('pig')
Out: 'ab'

4.注意事项

一 个正则表达式中可以包含多个子组

子组可以嵌套,但是不要重叠或者嵌套结构复杂

子组序列号一 般从外到内,从左到右计数

电子病例re正则解析与Python连接Sql Server 或Oracle数据库_第2张图片

Python re正则模块使用

regex = compile(pattern,flags = 0)
功能: 生产正则表达式对象
参数 : pattern 正则表达式
flags 功能标 志位, 扩展正则表达式的匹配
返回值: 正则表达式对象

re.findall(pattern,string,flags = 0)
功能: 根据正则表达式匹配目标 字符串内容
参数 : pattern 正则表达式
string 目标 字符串
flags 功能标 志位, 扩展正则表达式的匹配
返回值: 匹配到的内容列表, 如果正则表达式有子组则只能获取到子组对应的内容

regex.findall(string,pos,endpos)
功能: 根据正则表达式匹配目标 字符串内容
参数 : string 目标 字符串
pos 截取目标 字符串的开始匹配位置
endpos 截取目标 字符串的结束匹配位置
返回值: 匹配到的内容列表, 如果正则表达式有子组则只能获取到子组对应的内容

import re

s = '''Hello
北京'''
# regex = re.compile(r'\w',flags=re.A)#只能匹配ascii码['H', 'e', 'l', 'l', 'o']
# regex = re.compile(r'[a-z]+',flags=re.I)#匹配忽略字母大小写['Hello']
# regex = re.compile(r'.+')#['Hello', '北京']
# regex = re.compile(r'.+',flags= re.S)#使.可以匹配换行['Hello\n北京']
# regex = re.compile(r'^北京')#[]
# regex = re.compile(r'^北京',flags=re.M)#使^ $可以匹配每一行的开头结尾位置['北京']
# regex = re.compile(r'Hello$')#[]
regex = re.compile(r'Hello$',flags=re.M)#['Hello']

l = regex.findall(s)
print(l)

re.split(pattern,string,flags = 0)
功能: 使用正则表达式匹配内容, 切割目标 字符串
参数 : pattern 正则表达式
string 目标 字符串
flags 功能标 志位, 扩展正则表达式的匹配
返回值: 切割后的内容列表

re.sub(pattern,replace,string,max,flags = 0)
功能: 使用一 个字符串替换正则表达式匹配到的内容
参数 : pattern 正则表达式
replace 替换的字符串
string 目标 字符串
max 最多替换几处, 默认替换全部
flags 功能标 志位, 扩展正则表达式的匹配
返回值: 替换后的字符串

re.subn(pattern,replace,string,max,flags = 0)
功能: 使用一 个字符串替换正则表达式匹配到的内容
参数 : pattern 正则表达式
replace 替换的字符串
string 目标 字符串
max 最多替换几处, 默认替换全部
flags 功能标 志位, 扩展正则表达式的匹配
返回值: 替换后的字符串和替换了几处

import re
s = 'alex:1995,sunny:1991'
# 使用正则表达式匹配内容 , 切割目标字符串
l = re.split(r'[,:]',s)
print(l) #['alex', '1995', 'sunny', '1991']
# 使用一个字符串替换正则表达式匹配到的内容
# s = re.sub(r':','-',s,1)
# print(s) #alex-1995,sunny:1991
# 使用一个字符串替换正则表达式匹配到的内容
s = re.subn(r':','-',s,1)
print(s) #('alex-1995,sunny:1991', 1)

re.finditer(pattern,string,flags = 0)
功能: 根据正则表达式匹配目标 字符串内容
参数 : pattern 正则表达式
string 目标 字符串
flags 功能标 志位, 扩展正则表达式的匹配
返回值: 匹配结果的迭代器

import re
s = ' 今年是 2019 年 , 建国 70 周年 '
pattern = r'\d+' 匹配所有数字
item = re.finditer(pattern,s)
for i in item:
	print(i.group()) #2019 70

re.fullmatch(pattern,string,flags=0)
功能:完全匹配某个目标 字符串
参数 :pattern 正则
string 目标 字符串
返回值:匹配内容 match object

import re
s = " 今年是 2019 年 , 建国 70 周年 "
# 完全匹配
obj = re.fullmatch(r'.+',s)
print(obj.group())# 今年是 2019 年 , 建国 70 周年

re.match(pattern,string,flags=0)
功能:匹配某个目标 字符串开始位置
参数 :pattern 正则
string 目标 字符串
返回值:匹配内容 match object

import re
s = " 今年是 2019 年 , 建国 70 周年 "
# 匹配开始位置
obj = re.match(r'\w+',s)
print(obj.group()) # 今年是 2019 年

re.search(pattern,string,flags=0)
功能:匹配目标 字符串第一 个符合内容
参数 :pattern 正则
string 目标 字符串
返回值:匹配内容 match object

import re
s = " 今年是 2019 年 , 建国 70 周年 "
# 匹配第一处
obj = re.search(r'\d+',s)
print(obj.group()) #2019

compile 对象属性
【1 】 pattern : 正则表达式
【2 】 groups : 子组数 量
【3 】 groupindex : 捕获组名与组序号的字典

import re
#1.匹配一个.com邮箱格式的邮箱
print(re.findall(r'\w+@\w+\.com','[email protected]'))
#结果:['[email protected]']

#2.匹配一个密码8-12位,数字字母下划线构成
print(re.findall(r'\w{8,12}','zhiq14521'))
#结果:['zhiq14521']

#3.匹配一个数字,包含整数,小数,正数,负数,分数1/2及百分数4.6%
print(re.findall(r'-?\d+\.?/?\d*%?','1 -21 12.5 -12.8 0 1/3 4.6% '))
#结果:['1', '-21', '12.5', '-12.8', '0', '1/3', '4.6%']

#4.匹配一段文字中以大写字母开头的单词,注意文字中可能含有ipython这种,不算大写字母开头,H-base这种算大写字母开头,BSD也是.
print(re.findall(r'\b[A-Z][-_a-zA-Z]*','Hello iPython H-base BSD'))
#结果:['Hello', 'H-base', 'BSD']

#每个普通字符匹配其对应的字符,此处ab有两处,则结果也是两处
print(re.findall('ab','abcdefabcd'))
#结果:['ab', 'ab']

#匹配'|'或,两侧任意的正则表达式即可
print(re.findall('com|cn','www.baidu.com/www.twoo.cn'))
#结果:['com', 'cn']

#匹配除换行外的任意一个字符,其中.可以代替任意字符
print(re.findall('张.丰','张三丰,张无忌,张四丰'))
#结果:['张三丰', '张四丰']

#匹配字符集中的任意一个字符
print(re.findall('[aeiou]','how are you'))
#结果:['o', 'a', 'e', 'o', 'u']
print(re.findall('[A-Z]','Tom is Jam' ))
#结果:['T', 'J']

#匹配除了字符集以外的任意一个字符
print(re.findall('[^0-9]','use 007 port'))
#结果:['u', 's', 'e', ' ', ' ', 'p', 'o', 'r', 't']

#匹配目标字符串的开头位置
print(re.findall('^tom','tom is jame'))
#结果:['tom']

#匹配目标字符串的结尾位置
print(re.findall('tom$','jame is tom'))
#结果:['tom']

#匹配前面的字符出现0次或多次
print(re.findall('wo*','wooooooooooo--w!'))
#结果:['wooooooooooo', 'w']
print(re.findall('[a-z]*','Tom is not Jam'))
#结果:['', 'om', '', 'is', '', 'not', '', '', 'am', '']
print(re.findall('[A-Z][a-z]*','Tom is Jam'))
#结果:['Tom', 'Jam']

#匹配前面的字符出现1次或多次
print(re.findall('[A-Z][a-z]+',"Hello World  hello world  Hello World"))
#结果:['Hello', 'World', 'Hello', 'World']

#匹配前面的字符出现0次或1次
print(re.findall('-?[0-9]+',"Jame,age:18, -26"))
#结果:['18', '-26']
print(re.findall('[0-9]?',"Jame,age:18, -26"))
#结果:['', '', '', '', '', '', '', '', '', '1', '8', '', '', '', '2', '6', '']
print(re.findall('-?[0-9]',"Jame,age:18, -26"))
#结果:['1', '8', '-2', '6']
print(re.findall('-?[0-9]+','2019?redown-15'))
#结果:['2019', '-15']
print(re.findall('wo?','wooooo--w'))
#结果:['wo', 'w']

#匹配前面的字符出现n次,因为手机号码都是11位的,且第一位为1,后面十个在0-9中任意取.
print(re.findall('1[0-9]{10}',"Jame:13886495728"))
#结果:['13886495728']

#匹配前面的字符出现m-n次,因为qq都是10位,前五个在1-9中任意取一个,后5个在0-9中任意取一个
print(re.findall('[1-9][0-9]{5,10}',"Baron:1259296994"))
#结果:['1259296994']

# \d 匹配任意数字字符 \D 匹配任意非数字字符
print(re.findall('\d{1,5}',"Mysql: 3306, http:80"))
#结果:['3306', '80']
print(re.findall('\D{1,5}',"Mysql: 3306, http:80"))
#结果:['Mysql', ': ', ', htt', 'p:']

#\w 匹配普通字符,\W 匹配非普通字符
print(re.findall('\w+',"server_port = 8888"))
#结果:['server_port', '8888']
print(re.findall('\W+','server_port=8888'))
#结果:['=']

#\s 匹配空字符,\S 匹配非空字符
print(re.findall('\S+','hello  world'))
#结果:['hello', 'world']
print(re.findall('\s+','hello  world'))
#结果:['  ']
print(re.findall('\w+\s+\w+','hello world'))
#结果:['hello world']

#\A 表示开头位置,\Z 表示结尾位置,因为\w匹配普通字符,前后空字符被\A\Z匹配到了,加上连接+就是整个了.
print(re.findall('\A\w+\Z','Jame'))
#结果:['Jame']
print(re.findall('\A','Jame'))
#结果:['']
print(re.findall('\Z','Jame'))
#结果:['']

#\b 表示单词边界,\B 表示非单词边界
print(re.findall(r'\bis\b',"This is a test."))#is去除前后两端
#结果:['is']
print(re.findall('is','this is a test'))#两个is
#结果:['is', 'is']

print(re.findall(r'a*','abcdefg'))
#结果:['a', '', '', '', '', '', '', '']
print(re.findall('a*','abcdefg'))
#结果:['a', '', '', '', '', '', '', '']
print(re.findall(r'a+','abcdefg'))
#结果:['a']
print(re.findall('a+','abcdefg'))
#结果:['a']

print(re.findall('-?\d+\.?\d+','12 34 -1 1.56 -3.5'))
#结果:['12', '34', '1.56', '-3.5']
print(re.findall('-?\d+\.?\d*','12 34 -1 1.56 -3.5'))
#结果:['12', '34', '-1', '1.56', '-3.5']

print(re.findall('\$\d+','count:$100'))
#结果:['$100']
print(re.findall('$\d+','count:$100'))
#结果:[]
print(re.findall('\\$\\d+','count:$100'))
#结果:['$100']

print(re.findall(r'\(.+?\)',"(abcd)efgh(higk)"))
#结果:['(abcd)', '(higk)']
print(re.findall(r'\(.+\)',"(abcd)efgh(higk)"))
#结果:['(abcd)efgh(higk)']
print(re.findall(r'ab+','abababababab'))
#结果:['ab', 'ab', 'ab', 'ab', 'ab', 'ab']

print(re.search(r'(ab)+','abababab').group())
#结果:abababab
print(re.search(r'王|李\w{1,3}','王者荣耀').group())
#结果:王
print(re.search(r'王|李\w{1,3}','李世民').group())
#结果:李世民
print(re.search(r'(王|李)\w{1,3}','王者荣耀').group())
#结果:王者荣耀

print(re.search(r'(https|http|ftp|file)://\S+',"https://www.baidu.com").group(1))
#结果:https

print(re.search(r'(?Pab)+','ababababab').group('name'))
#结果:ab

print(re.search(r'\d+','360733199102200512').group())
#结果:360733199102200512
print(re.search(r'\d{18}','360733199102200512').group())
#结果:360733199102200512
print(re.search(r'\d{17}(\d|x)','36073319910220051x').group())
#结果:36073319910220051x

print(re.findall(r'(\w+):(\d+)','alex:1995,sunny:1991'))
#结果:[('alex', '1995'), ('sunny', '1991')]

match 对象的属性方法

1.属性变量

pos 匹配的目标 字符串开始位置

endpos 匹配的目标 字符串结束位置

re 正则表达式

string 目标 字符串

lastgroup 最后一 组的名称

lastindex 最后一 组的序号

2.属性方法

span() 获取匹配内容的起止位置

start() 获取匹配内容的开始位置

end() 获取匹配内容的结束位置

groupdict() 获取捕获组字典 ,组名为键,对应内容为值

groups() 获取子组对应内容

group(n = 0)
功能:获取 match 对象匹配内容
参数 :默认为 0表示 获取整个 match 对象内容,如果是序列号或者组名则表示 获取对应子组内容
返回值:匹配字符串

电子病例re正则解析与Python连接Sql Server 或Oracle数据库_第3张图片

import re
pattern = r'(ab)cd(?Pef)'
regex = re.compile(pattern)
info = regex.search('abcdefghi')#match 对象
# 属性变量
print(info.pos) #0
print(info.endpos) #9
print(info.re)#re.compile('(ab)cd(?Pef)')
print(info.string) #abcdefghi
print(info.lastgroup)#name
print(info.lastindex)#2
print('----------')
# 属性方法
print(info.span()) #(0, 6)
print(info.start()) #0
print(info.end()) #6
print(info.groups()) #('ab', 'ef')
print(info.groupdict()) #{'name': 'ef'}
print(info.group()) #abcdef
print(info.group('name')) #ef

flags 参数扩展

1.使用函数 :re模块调用的匹配函数 。如:re.compile,re.findall,re.search…

2.作用:扩展丰富正则表达式的匹配功能

3.常用 flag

> A == ASCII 元字符只能匹配 ascii> I == IGNORECASE 匹配忽略字母大小写
> S == DOTALL 使 . 可以匹配换行
> M == MULTILINE 使 ^ $可以匹配每一行的开头结尾位置

4.使用多个 flag
方法 :使用按位或连接

e.g. : flags = re.I | re.A
正则表达式示例
import re
s = '''Hello
北京 '''
regex = re.compile(r'\w',flags=re.A)
# 只能匹配 ascii 码 ['H', 'e', 'l', 'l', 'o']
regex = re.compile(r'[a-z]+',flags=re.I)
# 匹配忽略字母大小写 ['Hello']
regex = re.compile(r'.+') #['Hello', ' 北京 ']
regex = re.compile(r'.+',flags= re.S)
# 使 . 可以匹配换行 #['Hello\n 北京 ']
regex = re.compile(r'^ 北京 ') #[]
regex = re.compile(r'^ 北京 ',flags=re.M)
#[' 北京 ']
# 使 ^ $ 可以匹配每一行的开头结尾位置
regex = re.compile(r'Hello$') #[]
regex = re.compile(r'Hello$',flags=re.M)
#['Hello']
l = regex.findall(s)
print(l)
import re
def get_address(port):
    f = open('exc.txt', 'r')
    while True:#获取段落
        data = ''
        for line in f:
            if line == '\n':
                break
            data += line
        if not data:#文件已经结束
            break
        info = re.match(port,data)#判断是不是想要的段落
        if info:#如果info不是None说明找到目标段落
            print(data)
            # pattern = r'[0-9a-f]{4}\.[0-9a-f]{4}\.[0-9a-f]{4}'
            pattern = r'([0-9]{1,3}\.){3}[0-9]{1,3}/\d+|Unknow'
            address = re.search(pattern,data).group()
            return address

if __name__=='__main__':
    port = input('端口:')
    print(get_address(port))

文献解析示例

#文献解析第一步#clear_unusual.py:清理掉没有内容或者乱码的txt文档的程序
import os
import codecs
import pickle
import re
import json
from time import *

path = '//10.132.20.100/nlpdata/all/100100'

def scan_txt():
    '''
    遍历指定文件夹,显示文件夹所有文件名
    :return:
    '''
    file_list = []
    for root, dirs, files in os.walk(path):
        for file in files:
            if os.path.splitext(file)[1] == '.txt':
                file_list.append(os.path.join(root, file))
    return file_list

def process_txt(lines_list):
    '''
    循环清理掉所有乱码及扫描档文献
    :param lines_list:
    :return:
    '''
    cleat_list = []
    for line1 in lines_list:
        # print(line1)
        new_line = line1.strip()
        print(len(new_line))
        if re.search('^一、', new_line) or re.search('^二、', new_line) or re.search('\d%$', new_line) \
                or re.search('[*?+#&^@$]', new_line) or re.search('^(\d)', new_line) or re.search('(\d)$', new_line) \
                or re.search('.jpg', new_line) or re.search('\d$', new_line) or re.search('^\d', new_line) \
                or re.search('http', new_line) or re.search('www', new_line) or re.search('---*', new_line):
            continue
        else:
            cleat_list.append(new_line)
    return cleat_list

def main():
    '''
    清除所有以.pdf和.pdfbox.txt结尾的重复txt文件及清除所有扫描档文件并将其文件名保存再yichang01.txt文档中
    :return: 正常有数据的文件名保存在file01.txt文档中以便下次调用
    '''
    begin_time = time()
    file_list = scan_txt()
    print(file_list)
    print(len(file_list))
    for filename in file_list:
        if filename.endswith('.pdf.pdfbox.txt'):
            print(filename)
            with open('D:/liu/yichang01.txt', 'a+', encoding='utf-8') as f1:
                f1.write(filename + '\n')
        else:
            file1 = filename
            title_dict = {}
            lines_list = []
            with open(file1, 'r', encoding='utf-8', errors='replace') as f:
                for i in range(30):
                    lines = f.readline().strip()
                    lines_list.append(lines)
            print(lines_list)
            clear_list = process_txt(lines_list)
            print(clear_list)
            lines_str = ''.join(clear_list)
            title_dict[filename] = lines_str
            print(title_dict)
            for key in title_dict:
                if title_dict[key] == '':
                    with open('D:/liu/yichang01.txt', 'a+', encoding='utf-8') as f1:
                        f1.write(key + '\n')
                else:
                    with open('D:/liu/file01.txt', 'a+', encoding='utf-8') as f2:
                        f2.write(key + '\n')
    end_time = time()
    run_time = end_time - begin_time
    print('耗时:', run_time)

if __name__ == '__main__':
    main()
#文献解析第二步:title_recognition.py:识别出标题的程序。
import os
import codecs
import pickle
import re
import json
import csv
from time import *

path = '//10.132.20.100/nlpdata/all/100100'


def scan_txt():
    '''
    遍历指定文件夹,显示文件夹所有文件名
    :return:
    '''
    file_list = []
    for root, dirs, files in os.walk(path):
        for file in files:
            if os.path.splitext(file)[1] == '.txt':
                file_list.append(os.path.join(root, file))
    return file_list


def get_info(lines_list):
    '''
    循环迭代处理所有文件,返回每个文件前三十行的内容
    :param lines_list:
    :return:
    '''
    info_list = []
    for line in lines_list:
        new_line = line.strip()
        info_list.append(new_line)
    print(info_list)
    info_str = '***'.join(info_list)
    return info_str


def recognize_eng(info_dict):
    '''
    将中英文文献区分开,中文文献路径存在一个列表中,英文文献路径存入另一个列表中
    :param info_dict:
    :return:
    '''
    eng_dict = {}
    eng_list = []
    for key, value in info_dict.items():
        value2 = value.split('***')
        for value3 in value2:
            if re.search('[A-Za-z0-9]+', value3):
                lines = value3
                eng_list.append(lines)
                eng_dict[key] = eng_list
    return eng_dict


def process_txt(lines_list):
    '''
    循环清理掉所有文献的证券代码,公告编号
    :param lines_list:
    :return:
    '''
    clear_list = []
    for line1 in lines_list:
        new_line = line1
        if re.search('证券代码', new_line) or re.search('股票代码', new_line) or re.search('Stock ID', new_line) \
                or re.search('邮.*编', new_line) or re.search('Tel', new_line) or re.search('.*街.*号.*楼', new_line) \
                or re.search('^一、', new_line) or re.search('^二、', new_line) or re.search('^\d.*\d$', new_line) \
                or re.search('第.*页', new_line) or re.search('[*?+#&^@$]', new_line) or re.search('\dF', new_line):
            continue
        else:
            clear_list.append(new_line)
            if re.search('报.*告', new_line) or re.search('公.*告', new_line) or re.search('通.*知', new_line) \
                    or re.search('Notes', new_line) or re.search('Sheet', new_line) or re.search('Statement', new_line):
                break
    return clear_list


def process_txt2(lines_list2):
    '''
    循环清理掉所有文献的证券代码,公告编号
    :param lines_list2:
    :return:
    '''
    clear_list2 = []
    for line1 in lines_list2:
        new_line = line1
        if re.search('证券代码', new_line) or re.search('股票代码', new_line) or re.search('Stock ID', new_line) \
                or re.search('邮.*编', new_line) or re.search('Tel', new_line) or re.search('.*街.*号.*楼', new_line) \
                or re.search('^一、', new_line) or re.search('^二、', new_line) or re.search('^\d.*\d$', new_line) \
                or re.search('第.*页', new_line) or re.search('[*?+#&^@$]', new_line) or re.search('\dF', new_line):
            continue
        else:
            clear_list2.append(new_line)
            if re.search('报.*告', new_line) or re.search('公.*告', new_line) or re.search('通.*知', new_line) \
                    or re.search('Notes', new_line) or re.search('Sheet', new_line) or re.search('Statement', new_line):
                break
    return clear_list2


def recognize_title(clear_list):
    '''
    循环筛选出所有文献的标题
    :param clear_list:
    :return:
    '''
    title_list = []
    for line1 in clear_list:
        line2 = line1.strip()
        if not re.search('[,:。、!√]', line2) and not re.search('序.*号', line2) and not re.search('页.*次', line2):
            title_list.append(line2)
        else:
            break
    print(title_list)
    title_set = sorted(set(title_list), key=title_list.index)
    title_str = ''.join(title_set)
    print(title_str)


def recognize_title2(clear_list2):
    '''
    循环筛选出所有文献的标题
    :param clear_list:
    :return:
    '''
    title_list = []
    for line1 in clear_list2:
        line2 = line1.strip()
        if not re.search('[,:.!√]', line2) and not re.search('序.*号', line2) and not re.search('页.*次', line2):
            title_list.append(line2)
        else:
            break
    print(title_list)
    title_set = sorted(set(title_list), key=title_list.index)
    title_str = ''.join(title_set)
    print(title_str)


def remove_blank(title_dict):
    '''
    循环删除所有文献标题的空格
    :param title_dict:
    :return:
    '''
    clear_title_dict = {}
    lines_list = []
    for key, value in title_dict.items():
        if re.search('[A-Za-z0-9]+', value):
            lines = value
        else:
            lines = ''.join(value.split())
        lines_list.append(lines)
        title_set = sorted(set(lines_list), key=lines_list.index)
        clear_title = ''.join(title_set)
        clear_title_dict[key] = clear_title
    return clear_title_dict


def make_tag(clear_title_dict):
    '''
    循环按规则给所有文件的标题打上标签
    :param clear_title_dict:
    :return:
    '''
    key_list = []
    label_list = []
    for key, value in clear_title_dict.items():
        key_list.append(key)
        if re.search('公告', value) or re.search('Announcement', value) or re.search('announcement', value):
            label = '公告'
        elif re.search('章程', value) or re.search('ARTICLES', value):
            label = '章程'
        elif re.search('报告', value) or re.search('快报', value) or re.search('Report', value):
            label = '报告'
        elif re.search('办法', value):
            label = '办法'
        else:
            label = 'None'
        label_list.append(label)
    return label_list


def output_tag(clear_title_dict, label_list):
    '''
    输出文件路径,标签,以便后续查找出无标签的情况
    :param clear_title_dict:
    :param label_list:
    :return:
    '''
    key_list = []
    label_dict = {}
    for key in clear_title_dict:
        key_list.append(key)
    for filename, label in zip(key_list, label_list):
        label_dict[filename] = label
    return label_dict


def output_json(clear_title_dict, label_list):
    '''
    输出最后结果,含文献路径,标题,标签
    :param clear_title_dict:
    :param label_list:
    :return:
    '''
    key_list = []
    value_list = []
    result = {}
    for key, value in clear_title_dict.items():
        key_list.append(key)
        value_list.append(value)
    for filename, Title, label in zip(key_list, value_list, label_list):
        result[filename] = {Title: label}
    return result


def output_data(clear_title_dict, label_list):
    '''
    输出最后结果,含文献路径,标题,标签
    :param clear_title_dict:
    :param label_list:
    :return:
    '''
    key_list = []
    value_list = []
    for key, value in clear_title_dict.items():
        key_list.append(key)
        value_list.append(value)
    for filename, Title, label in zip(key_list, value_list, label_list):
        consequence = {
            'payload': {
                'result': {
                    'data': [{
                        'fileID': filename,
                        'title': Title,
                        'label': label
                    }],
                    'totalCount': 1
                },
                'success': 'true'
            },
        }
        return consequence


def output_info(clear_title_dict, label_list, info_dict):
    '''
    输出最后结果:含文献路径,文献内容,标题,标签
    :param clear_title_dict:
    :param label_list:
    :param info_dict:
    :return:
    '''
    key_list = []
    value_list = []
    content_list = []
    show_dict = {}
    for key, value in clear_title_dict.items():
        key_list.append(key)
        value_list.append(value)
    for content in info_dict.values():
        content_list.append(content)
    for filename, info, Title, label in zip(key_list, content_list, value_list, label_list):
        show_dict[filename] = {info: {Title: label}}
    return show_dict


def main():
    '''
    清除所有以.pdf和.pdfbox.txt结尾的重复txt文件及清除所有扫描档文件并将其文件名保存再yichang01.txt文档中
    :return: 正常有数据的文件名保存在file01.txt文档中以便下次调用
    '''
    begin_time = time()
    file_list = scan_txt()
    with open('test01.csv', 'a+', newline='', encoding='utf-8') as f7:
        writer = csv.writer(f7, dialect='excel')
        header = ['文件名', '标题候选文本', '文本标题', '文本类型']
        writer.writerow(header)
    with open('D:/liu/file01.txt', 'r', encoding='utf-8') as f1:
        data_list = f1.readlines()
        for data in data_list:
            data1 = data.strip('\n')
            title_dict = {}
            info_dict = {}
            lines_list = []
            lines_list2 = []
            with open(data1, 'r', encoding='utf-8', errors='replace') as f:
                for i in range(30):
                    lines = f.readline()
                    lines_list.append(lines)
            print(data1)
            print(lines_list)
            info_str = get_info(lines_list)
            info_dict[data1] = info_str
            print(info_dict)
            eng_dict = recognize_eng(info_dict)
            print(eng_dict)
            clear_list = process_txt(lines_list)
            print(clear_list)
            title_str = recognize_title(clear_list)
            title_dict[data1] = title_str
            print(title_dict)
            for key1 in title_dict:
                if title_dict[key1] == '':
                    with open(key1, encoding='utf-8', errors='replace') as f1:
                        for i in range(30):
                            lines2 = f1.readline().strip()
                            lines_list2.append(lines2)
                    clear_list2 = process_txt2(lines_list2)
                    title_str02 = recognize_title2(clear_list2)
                    title_dict[key1] = title_str02
            print(title_dict)
            for key2 in title_dict:
                if title_dict[key2] == '':
                    with open('D://liu/file60.txt', 'a+', encoding='utf-8') as f2:
                        f2.write(key2 + '\n')
            for key in list(title_dict.keys()):
                if not title_dict.get(key):
                    del title_dict[key]
            clear_title_dict = remove_blank(title_dict)
            label_list = make_tag(clear_title_dict)
            label_dict = output_tag(clear_title_dict, label_list)
            print(label_dict)
            for key3 in label_dict:
                if label_dict[key3] == 'None':
                    with open('D:/liu/file70.txt', 'a+', encoding='utf-8') as f8:
                        f8.write(key3 + '\n')
            result = output_json(clear_title_dict, label_list)
            consequence = output_data(clear_title_dict, label_list)
            print(consequence)
            print(type(consequence))
            print(result)
            result_json = json.dumps(result, ensure_ascii=False)
            consequence_json = json.dumps(consequence, ensure_ascii=False, indent=4)
            with open('D:/liu/test01.json', 'a+', encoding='utf-8') as f3:
                f3.write(result_json + '\n')
            with open('D:/liu/test01.txt', 'a+', encoding='utf-8') as f4:
                f4.write(result_json + '\n')
            with open('D:/liu/test10.json', 'a+', encoding='utf-8') as f5:
                f5.write(consequence_json + '\n')
            with open('D:/liu/test10.txt', 'a+', encoding='utf-8') as f6:
                f6.write(consequence_json + '\n')
            show_dict = output_info(clear_title_dict, label_list, info_dict)
            print(show_dict)
            with open('test01.csv', 'a+', newline='', encoding='utf-8') as f7:
                writer = csv.writer(f7, dialect='excel')
                for key10, value10 in show_dict.items():
                    for key20, value20 in value10.items():
                        for key30, value30 in value20.items():
                            writer.writerow([key10, key20, key30, value30])

    end_time = time()
    run_time = end_time - begin_time
    print('耗时:', run_time)


if __name__ == '__main__':
    main()

电子病例re正则解析与Python连接Sql Server 或Oracle数据库_第4张图片

四:电子病例re正则解析

步骤一:借助sql语句查询出相应字段,提取信息,并得出其数据类型及整体数据结构;

步骤二:sql语句查询得数据类型为列表,一个个调出其中的字段,找到需要解析的字段(lxnr_bj);

步骤三:re正则结合体温关键字(T,体温,℃,度,°)解析的字段(lxnr_bj)得体温字段信息 ;

步骤四:re正则结合血压关键字(Bb,Pp,mmHg,血压)解析的字段(lxnr_bj)得收缩压,舒张压字段信息 ;

步骤五:re正则结合血压关键字(P,次/分,心率)解析的字段(lxnr_bj)得脉搏字段信息;

步骤六:re正则结合呼吸关键字(R,r,次/分,呼吸)解析的字段(lxnr_bj)得脉搏字段信息;

步骤七:连接Oracle数据库,将解析后得数据插入数据库,实现数据入库入表。

def aaa(self, a, b):
    blType = 'mzbl'
    sql_bj = "select y.KSSJ, m.BRID, m.MZHM, m.BRXM, m.jtdh lxdh, w.JLXH jlxh, w.BRTGJC DLNR, '' BLBH, w.JZXH jzxh from  his_bj_hc.MS_BRDA m \
    inner join  his_bj_hc.YS_MZ_JZLS y on y.brbh=m.brid \
    inner join  his_bj_hc.OMR_BLZY w on w.jzxh=y.jzxh \
    where M.ZXBZ<>1  \
    and (w.BRTGJC like '%℃%' or w.BRTGJC like '%度%' or w.BRTGJC like '%T%' or w.BRTGJC like '%°%' or w.BRTGJC like '%mmHg%' \
    or w.BRTGJC like '%分%' or w.BRTGJC like '%次%' or w.BRTGJC like '%P%' or w.BRTGJC like '%R%'  or w.BRTGJC like '%p%' or w.BRTGJC like '%r%') \
    and rownum<=10\
    order by y.KSSJ , w.JLXH "
    db_get = opdb_get()
    cursor = db_get.cursor()
    sj_bj = cursor.execute(sql_bj).fetchall()
    # 连接oracle库并从原始readonly用户中查询到所需信息,主功能:查
    print(type(sj_bj))	#
    print(sj_bj)#[(datetime.datetime(2018, 1, 9, 0, 40, 44), 12109414, '91258149', '李建云', '13538286432', 387, '神志清,T{数字}℃,BP{收缩压}/{舒张压}mmHg,心率{心率数值}次/分。', None, 377), (datetime.datetime(2018, 1, 9, 0, 43, 37), 12109415, '91258150', '张万锦', '13682650486', 388, '神志清,T37℃,BP126/80mmHg,心率76次/分。神志清楚,查体合作,一般情况可,心肺听诊无异常,腹平软,无压痛,无反跳痛,墨菲氏征(—),右侧肾区叩击痛,肠鸣音3次/分钟。', None, 378), (datetime.datetime(2018, 12, 6, 20, 29, 8), 12389299, '91775912', '吴灏', '13510250655', 174, '神志清,T37℃,心率120次/分,R 32次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体I°肿大,未见脓点,呼吸平顺,双肺呼吸音粗,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,肝脾肋下未触及,肠鸣音正常,肌张力正常。生理反射存在,病理反射未引出。手足未见皮疹。躯干部散在红色皮疹', None, 629825), (datetime.datetime(2018, 12, 6, 20, 29, 19), 12259981, '91526408', '徐莉涵', '13691859246', 251, '神志清,T37℃,心率120次/分,R 32次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体I°肿大,未见脓点,呼吸平顺,双肺呼吸音粗,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,肝脾肋下未触及,肠鸣音正常,肌张力正常。生理反射存在,病理反射未引出。手足未见皮疹。', None, 629826), (datetime.datetime(2018, 12, 6, 20, 31, 16), 12126230, '91284569', '韦建璋', '18819009635', 192, '神志清,T36.5℃,BP120/80mmHg,心率80次/分。神志清楚,对答切题,伸舌不偏,瞳孔等大圆,光反射敏感,心肺无异常,腹平软,右上腹压痛(+)反跳痛(-),四肢无异常。', None, 629827), (datetime.datetime(2018, 12, 6, 20, 33, 27), 12295293, '91598597', '符帼英', '15767901698', 171, 'P72 次/分,神志清晰,颈软.甲状腺Ⅰ、II度肿大,无压痛,无血管杂音,双肺无异常,心率72次/分,律齐,未闻及杂音,腹平软.腹部无压痛、反跳痛,四肢无异常。', None, 629829), (datetime.datetime(2018, 12, 6, 20, 37, 32), 10688789, '902923800', '温召杰', '13510659001', 233, 'T:36 ℃.P:74次/分.R:19 次/分.BP:125 /75 mmHg.神志清楚,呼吸平稳,双肺呼吸音清晰,未闻及干湿罗音。心率74次/分,律齐,各瓣音区未闻及病理性杂音。腹平软,无压痛、反跳痛,双下肢不肿,四肢活动好。\r\n既往史及个人史同前。', None, 629831), (datetime.datetime(2018, 12, 6, 20, 40, 52), 12336048, '91676335', '马一菡', '13530615698', 224, '神志清,T37.3℃P 120次/分,R 30次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体无肿大,未见脓点,,双肺呼吸音清晰,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,全腹未扪及包块肝脾肋下未触及,肠鸣音活跃,肌张力正常。生理反射存在,病理反射未引出。手足未见皮疹。', None, 629833), (datetime.datetime(2018, 12, 6, 20, 40, 55), 12427232, '91849563', '张海荣', '13751080051', 170, 'T:37.9 ℃.P:78 次/分.R:19 次/分.BP:110 /70 mmHg.神志清楚,咽部充血.扁桃体无肿大.咽后壁滤泡增生.呼吸平稳,双肺呼吸音清晰,未闻及干湿罗音。心率78次/分,律齐,各瓣音区未闻及病理性杂音。腹平软,无压痛、反跳痛,双下肢不肿,四肢活动好。神志清,T{数字}℃,BP{收缩压}/{舒张压}mmHg,心率{心率数值}次/分。', None, 629834), (datetime.datetime(2018, 12, 6, 20, 43, 24), 12199534, '91408374', '汤诗琪', '13682569396', 169, '神志清,T38.3℃,心率120次/分,R 22次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体I°肿大,未见脓点,呼吸平顺,双肺呼吸音粗,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,肝脾肋下未触及,肠鸣音正常,肌张力正常。生理反射存在,病理反射未引出。手足未见皮。', None, 629835)]
    
#以上为步骤一:借助sql语句查询出相应字段,提取信息,并得出其数据类型及整体数据结构。
    
    for res_bj in sj_bj:
        jzxh_bj = res_bj[8]
        dt_bj = res_bj[0]
        rq_bj = dt_bj.strftime('%Y-%m-%d %H:%M:%S')
        BRXM_bj = res_bj[3]
        lxdh_bj = res_bj[4]
        lsh_bj = res_bj[5]
        mzh_bj = res_bj[2]
        brid_bj = res_bj[1]
        blbh_bj = res_bj[7]
        lxnr_bj = res_bj[6]
        print(lxnr_bj)
        #神志清,T{数字}℃,BP{收缩压}/{舒张压}mmHg,心率{心率数值}次/分。
        #神志清,T37℃,BP126/80mmHg,心率76次/分。神志清楚,查体合作,一般情况可,心肺听诊无异常,腹平软,无压痛,无反跳痛,墨菲氏征(—),右侧肾区叩击痛,肠鸣音3次/分钟。
        #神志清,T37℃,心率120次/分,R 32次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体I°肿大,未见脓点,呼吸平顺,双肺呼吸音粗,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,肝脾肋下未触及,肠鸣音正常,肌张力正常。生理反射存在,病理反射未引出。手足未见皮疹。躯干部散在红色皮疹
		#神志清,T37℃,心率120次/分,R 32次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体I°肿大,未见脓点,呼吸平顺,双肺呼吸音粗,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,肝脾肋下未触及,肠鸣音正常,肌张力正常。生理反射存在,病理反射未引出。手足未见皮疹。
        #神志清,T36.5℃,BP120/80mmHg,心率80次/分。神志清楚,对答切题,伸舌不偏,瞳孔等大圆,光反射敏感,心肺无异常,腹平软,右上腹压痛(+)反跳痛(-),四肢无异常。
		#P72 次/分,神志清晰,颈软.甲状腺Ⅰ、II度肿大,无压痛,无血管杂音,双肺无异常,心率72次/分,律齐,未闻及杂音,腹平软.腹部无压痛、反跳痛,四肢无异常。
        #T:36 ℃.P:74次/分.R:19 次/分.BP:125 /75 mmHg.神志清楚,呼吸平稳,双肺呼吸音清晰,未闻及干湿罗音。心率74次/分,律齐,各瓣音区未闻及病理性杂音。腹平软,无压痛、反跳痛,双下肢不肿,四肢活动好。既往史及个人史同前。
        #神志清,T37.3℃P 120次/分,R 30次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体无肿大,未见脓点,,双肺呼吸音清晰,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,全腹未扪及包块肝脾肋下未触及,肠鸣音活跃,肌张力正常。生理反射存在,病理反射未引出。手足未见皮疹。
		#T:37.9 ℃.P:78 次/分.R:19 次/分.BP:110 /70 mmHg.神志清楚,咽部充血.扁桃体无肿大.咽后壁滤泡增生.呼吸平稳,双肺呼吸音清晰,未闻及干湿罗音。心率78次/分,律齐,各瓣音区未闻及病理性杂音。腹平软,无压痛、反跳痛,双下肢不肿,四肢活动好。神志清,T{数字}℃,BP{收缩压}/{舒张压}mmHg,心率{心率数值}次/分。
		#神志清,T38.3℃,心率120次/分,R 22次/分。神志清楚,精神反应可,全身皮肤无黄染、皮疹,结膜无充血,眼球运动自如,鼻翼无扇动,唇红,无杨梅舌,咽部充血,未见疱疹,双侧扁桃体I°肿大,未见脓点,呼吸平顺,双肺呼吸音粗,未闻及干湿罗音,心音有力,律齐,各瓣膜听诊区未闻及杂音;腹平软,肝脾肋下未触及,肠鸣音正常,肌张力正常。生理反射存在,病理反射未引出。手足未见皮。
        
#以上为步骤二:sql语句查询得数据类型为列表,一个个调出其中的字段,找到需要解析的字段(lxnr_bj)

        lxnr_bj = lxnr_bj.replace('\n', '')
        lxnr_bj = lxnr_bj.replace('\r', '')
        lxnr_bj = lxnr_bj.replace("'", '')
        lxnr_bj = lxnr_bj.replace(" ", '')
        #消除lxnr_bj字段字符串中间的的空格:如(BP:125 /75 mmHg)变成(BP:125/75mmHg)方便后续re正则匹配收缩压等.
        #取出的单个lxnr_bj字段为字符串类型,采用上面三行代码替换消除掉字符串中的换行符,制表符,空格等
        soup_bj = BeautifulSoup(lxnr_bj, "html.parser", from_encoding="utf-8")
        # BeautifulSoup最主要的功能是从网页抓取数据。提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。
		# 它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
		# 自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,
		# 这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
        rewb_bj = re.compile('<[^>]+>')
        soup_bj = rewb_bj.sub("", str(soup_bj))
        #上述三行为多余重复代码
        qjcs_bj = ''
        bqbh_bj = ''
        wd_bj = ''
        ssy_bj = ''
        szy_bj = ''
        mb_bj = ''
        hx_bj = ''
        wd_resout_bj = re.findall(r'[T(体温)(温度)(T{)(T{数字})][::]? *[1-9]\d*[\.,,]?\d*|[1-9]\d*[\.,,]?\d*[℃度°]', str(lxnr_bj), re.S)
        print(wd_resout_bj)
        #正则匹配出(lxnr_bj字段)中的体温标志数据[] ['T37'] ['T37'] ['T37'] ['T36.5'] [] 												['T:36'] ['T37.3'] ['T:37.9'] ['T38.3']
        if wd_resout_bj:
            #如果wd_resout_bj非空,则执行下行代码,清除文字,字母,保留数字
            wd_resout_bj = re.findall(r'[1-9]\d*[\.,,]?\d*|0\.\d*[1-9]\d*', str(wd_resout_bj[0]), re.S)
            print(wd_resout_bj)
         #正则匹配出(lxnr_bj字段)中的体温数值数据 ['37'] ['37'] ['37'] ['36.5']  														['36'] ['37.3'] ['37.9'] ['38.3']
            if wd_resout_bj:
                wd_bj = wd_resout_bj[0].strip()
                print(wd_bj)
                #消除wd_resout_bj每个列表元素的前后空格,保留数字,即提取体温值(体温字段:wd_bj)
        str1_bj = '体温-' + wd_bj
        # print(str1_bj)
        
#以上为步骤三:re正则结合体温关键字(T,体温,℃,度,°)解析的字段(lxnr_bj)得体温字段信息    
            
        xy_resout_bj = re.findall(r'[Bb][Pp][::]?[^mmHg]*mmHg', str(lxnr_bj), re.S)
        print(xy_resout_bj)
        # 正则匹配出(lxnr_bj字段)中的血压标志数据['BP{收缩压}/{舒张压}mmHg'] ['BP126/80mmHg']
        							[] [] ['BP120/80mmHg'] [] ['BP:125 /75 mmHg']
            						[] ['BP:110 /70 mmHg', 'BP{收缩压}/{舒张压}mmHg'] []
        if xy_resout_bj:
            #如果xy_resout_bj非空,则执行下行代码,清除收缩压或BP等标志,保留数字到\或/结束
            ssy_resout_bj = re.findall(r'[1-9]\d*\/', str(xy_resout_bj[0]), re.S)
            print(ssy_resout_bj)#取出收缩压:[] ['126/'] ['120/'] ['125/'] ['110/']
            if ssy_resout_bj:
                ssy_resout_bj = re.findall(r'[1-9]\d*', str(ssy_resout_bj[0]), re.S)
                print(ssy_resout_bj)#清除\或/取出收缩压数值['126'] ['120'] ['125'] ['110']
                if ssy_resout_bj:
                    ssy_bj = ssy_resout_bj[0]
                    print(ssy_bj)#列表取出收缩压数值126 120 125 110即(收缩压字段:ssy_bj)
                    
            szy_resout_bj = re.findall(r'\/[1-9]\d*', str(xy_resout_bj[0]), re.S)
            print(szy_resout_bj)#取出舒张压:[] ['/80'] ['/80'] ['/75'] ['/70']
            if szy_resout_bj:
                szy_resout_bj = re.findall(r'[1-9]\d*', str(szy_resout_bj[0]), re.S)
                if szy_resout_bj:
                    szy_bj = szy_resout_bj[0]
                    print(szy_bj)#列表取出舒张压数值80 80 75 70即(收缩压字段:szy_bj)
        str1_bj += ';血压-' + ssy_bj + '-' + szy_bj
        
#以上为步骤四:re正则结合血压关键字(Bb,Pp,mmHg,血压)解析的字段(lxnr_bj)得收缩压,舒张压字段信息 
        
        mb_resout_bj = re.findall(r'[Pp][::]?[^次\/分]*次\/分|[Pp][::]?[^bpm]*bpm|心率[::]?[^次\/分]*次\/分',str(lxnr_bj),re.S)
        print(mb_resout_bj)
        # 正则匹配出(lxnr_bj字段)中的心率标志数据['心率{心率数值}次/分'] ['心率76次/分']
['心率120次/分'] ['心率120次/分'] ['心率80次/分'] ['P72次/分', '心率72次/分'] 
['P:74次/分', '心率74次/分'] ['P120次/分'] ['P:78次/分', '心率78次/分', '心率{心率数值}次/分'] ['心率120次/分']
        if mb_resout_bj:
            mb_resout_bj = re.findall(r'[1-9]\d*', str(mb_resout_bj[0]), re.S)
            print(mb_resout_bj)#清除汉字或字母取出心率数值[]['76']['120']['120']['80']['72']														 ['74']['120']['78']['120']
            if mb_resout_bj:
                mb_bj = mb_resout_bj[0]
                print(mb_bj)#列表取出心率数值76 120 120 80 72 74 120 78 120即脉搏字段:mb_bj
        str1_bj += ';脉搏/心率-' + mb_bj
        
#以上为步骤五:re正则结合血压关键字(P,p,次\/分,心率)解析的字段(lxnr_bj)得脉搏字段信息 
        
        hx_resout_bj = re.findall(r'[Rr][::]?[^次\/分]*次\/分|呼吸[::]?[^次\/分]*次\/分', str(lxnr_bj), re.S)
        print(hx_resout_bj)
        # 正则匹配出(lxnr_bj字段)中的呼吸标志数据[] [] ['R32次/分'] ['R32次/分'] [] [] 
['R:19次/分', '呼吸平稳,双肺呼吸音清晰,未闻及干湿罗音。心率74次/分'] ['R30次/分']
['R:19次/分', '呼吸平稳,双肺呼吸音清晰,未闻及干湿罗音。心率78次/分'] ['R22次/分']
        if hx_resout_bj:
            hx_resout_bj = re.findall(r'[1-9]\d*', str(hx_resout_bj[0]), re.S)
            print(hx_resout_bj)#清除汉字或字母取出呼吸数值['32']['32']['19']['30']['19']['22']
            if hx_resout_bj:
                hx_bj = hx_resout_bj[0]
                print(hx_bj)#列表取出呼吸数值32 32 19 30 18 22即脉搏字段:hx_bj
        str1_bj += ';呼吸-' + hx_bj
        print(str1_bj)  
        
#以上为步骤六:re正则结合呼吸关键字(R,r,次\/分,呼吸)解析的字段(lxnr_bj)得脉搏字段信息

	db_save = opdb_save()
    cursor1 = db_save.cursor()
    # 连接oracle库的目标用户,用于存储上述查询到所需信息,主功能:连接
    r1_bj = "INSERT INTO test_liu (ID,Brid, Mzh,jzxh,BLBH,Lsh,Title,wd,ssy,szy,mb,hx,lxdh,NR,Type,RECORD_TIME,BRXM,EXTRACT_TIME)VALUES({0},'{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}','{13}','{14}','{15}','{16}',{17})".format('BJ_EY_MZBL_SEQ_ID.nextval', str(brid_bj), str(mzh_bj), str(jzxh_bj), str(blbh_bj), str(lsh_bj), '体格检查',str(wd_bj), str(ssy_bj), str(szy_bj), str(mb_bj),str(hx_bj), str(lxdh_bj), str(lxnr_bj), str(blType), str(rq_bj), str(BRXM_bj), 'sysdate')
    cursor1.execute(r1_bj)
    db_save.commit()
    cursor1.close()
    db_save.close()
    # 连接oracle的目标用户,主要功能:解析好的数据入库,即功能:oracle数据入库。	
    
#以上为步骤七:连接Oracle数据库,将解析后得数据插入数据库,实现数据入库入表。
                
if __name__ == '__main__':
    aaa("a", "b")#调用def aaa(self, a, b)函数

效果展示如图所示:

电子病例re正则解析与Python连接Sql Server 或Oracle数据库_第5张图片

Re正则解析电子病例总结:主要是利用re正则匹配特征关键字,注意开头/末尾关键字就行。

你可能感兴趣的:(re正则,python,数据库的使用,sql,json,pycharm,python,正则表达式)