当前位置:   article > 正文

Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例_搭建ftp多线程服务器

搭建ftp多线程服务器

本文实例讲述了Python实现基于多线程、多用户的FTP服务器与客户端功能。分享给大家供大家参考,具体如下:

项目介绍:

1. 用户加密认证
2. 允许同时多用户登录
3. 每个用户有自己的家目录 ,且只能访问自己的家目录
4. 对用户进行磁盘配额,每个用户的可用空间不同
5. 允许用户在ftp server上随意切换目录
6. 允许用户查看当前目录下文件
7. 允许上传和下载文件,保证文件一致性
8. 文件传输过程中显示进度条

实现的原理:

服务器端启用端口监听,并对每一连接启用一个线程,对用户登陆密码采用SHA512进行加密并进行匹配,当用户登陆成功后,实例化FTPS,并引导客户端进入主命令模式,

然后实现FTP的上传功能、下载功能、新建目录、删除文件或目录、切换目录等实例化操作,同时对相关上传下载进行进度条显示,服务器端显示下载或上传文件的大小等

客户端与服务器协商建立连接后,进行用户身份登陆,登陆成功接收服务器指令,转入命令输入窗口,同时对put 与 get命令进行判断,实现特定的上传与下载功能

核心代码实现如下:

服务器端

main.py

  1. #!/usr/bin/env python3.5
  2. # -*-coding:utf8-*-
  3. import os,sys,socket,pickle
  4. BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  5. sys.path.append(BASEDIR)
  6. from conf import setting
  7. from core import file_handler
  8. from core import db_handler
  9. import select,hashlib
  10. import threading
  11. def login(username,password):
  12. """
  13. FTP登陆验证函数
  14. :param username:
  15. :param password:
  16. :return:
  17. # testDict ={"username":"jjb","password":"123456","file_dir":"E:\python","file_size":500}
  18. # file = 'jjb.pkl'
  19. # fp = open(file,'wb')
  20. # pickle.dump(testDict,fp)
  21. # fp.close()
  22. f = open("jjb.pkl","rb")
  23. data = pickle.loads(f.read())
  24. f.close()
  25. print(data)
  26. """
  27. #实例化加密函数
  28. hash = hashlib.sha512()
  29. db= db_handler.handler(setting.DATABASE,username)
  30. if os.path.isfile(db):
  31. f = open(db,"rb")
  32. data = pickle.loads(f.read())
  33. f.close()
  34. if username == data["name"]:
  35. hash.update(bytes(data["password"],"utf8"))
  36. hash_pwd = hash.hexdigest()
  37. if hash_pwd == password:
  38. filedir = data["file_dir"]
  39. filesize = data["file_size"]
  40. return "True|%s|%s"%(filedir,filesize)
  41. else:
  42. return "False||"
  43. else:
  44. return "False||"
  45. else:
  46. return "False||"
  47. def process(conn,addr):
  48. flage = "False"
  49. # 接收客户端连接请求信息
  50. info = conn.recv(1000)
  51. if info.decode() == "connect":
  52. conn.send(bytes("login","utf8"))
  53. # 接收用户及密码信息
  54. while flage =="False":
  55. user_check =conn.recv(8000)
  56. # 分割用户名及密码
  57. username,password = str(user_check.decode()).split("|")
  58. # 调用登陆验证函数
  59. login_ack = login(username,password)
  60. flage,home,size = str(login_ack).split("|")
  61. # print(flage,home,size)
  62. # print("user_input:",username,"user_pass:",password)
  63. if flage =="True":
  64. # 登陆成功发送登陆确认信息给客户端
  65. conn.send(bytes("login_ack","utf8"))
  66. # 实例化FTPserver
  67. ftp = file_handler.FTPs(username,conn,home,size) # 登陆用户,数据连接,工作目录,磁盘配额
  68. ftp.run()
  69. break
  70. else:
  71. # 登陆失败,发送给客户端重新验证
  72. conn.send(bytes("登陆失败!","utf8"))
  73. def ftp_server():
  74. '''
  75. 启动FTP服务器端,开启线程监听
  76. :return:
  77. '''
  78. server = socket.socket()
  79. server.bind((setting.IP_PORT["host"],setting.IP_PORT["port"]))
  80. server.listen(10)
  81. while True:
  82. r,w,e = select.select([server,], [], [], 1)
  83. for i,server in enumerate(r):
  84. conn,addr = server.accept()
  85. # 创建线程
  86. t = threading.Thread(target=process, args=(conn, addr))
  87. # 启动线程
  88. t.start()
  89. server.close()
  90. def run():
  91. ftp_server()
  92. if __name__ =="__main__":
  93. run()

file_handler.py:

  1. #!/usr/bin/env python3.5
  2. # -*-coding:utf8-*-
  3. import os,sys
  4. BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  5. sys.path.append(BASEDIR)
  6. import re
  7. from core import db_handler
  8. from conf import setting
  9. import pickle
  10. class FTPs(object):
  11. '''
  12. ftp操作命令方法:
  13. '''
  14. def __init__(self,username,conn,home,total_size):
  15. '''
  16. 初始化参数
  17. :param username: 操作用户名
  18. :param conn: sock连接
  19. :param home: 用户根目录
  20. :param total_size: 磁盘配额
  21. :return:
  22. '''
  23. self.username = username
  24. self.conn = conn
  25. self.root = home
  26. self.home = self.root
  27. self.total_size = int(total_size)
  28. self.cmd_file = None # 文件指令
  29. self.psize = 4096 # 文件分片
  30. def getdirsize(self,space):
  31. '''
  32. 计算磁盘空间大小
  33. :return:
  34. '''
  35. self.dirsize = 0
  36. for root,dirs,files in os.walk(space):
  37. self.dirsize += (sum([os.path.getsize(os.path.join(root,name))for name in files])/1024)
  38. return int(self.dirsize)
  39. def put(self):
  40. '''
  41. 上传文件
  42. :return:
  43. '''
  44. if self.cmd_file:
  45. self.user_space = int(self.getdirsize(self.root)/1024)
  46. # 组合接收字符串
  47. self.file_root = '%s\\%s'% (self.home,self.cmd_file)
  48. # # 获取文件名
  49. self.f =os.path.basename(self.file_root)
  50. if os.path.isdir(self.home):
  51. os.chdir(self.home)
  52. else:
  53. os.makedirs(self.home)
  54. os.chdir(self.home)
  55. try:
  56. self.conn.send(bytes("f_ack","utf8"))
  57. self.size = str(self.conn.recv(1024).decode()).split("|")
  58. if self.size[0]== "fsize":
  59. self.fss = int(self.size[1])
  60. self.f_total_size = int(self.user_space + (self.fss/1024/1024))
  61. if self.f_total_size < self.total_size: # 判断空间是否超额
  62. self.conn.send(bytes("f_ack_ready","utf8"))
  63. self.bsize = 0
  64. print("需要上传文件大小:",self.fss)
  65. # 打开文件
  66. f=open(self.f,'wb')
  67. while self.bsize < self.fss:
  68. data = self.conn.recv(self.psize)
  69. self.bsize += len(data)
  70. f.write(data)
  71. self.conn.send(bytes("ok","utf8"))
  72. print("实际已上传文件大小:",self.bsize)
  73. else:
  74. self.conn.send(bytes("上传空间不足!无法上传,你当前磁盘配额为%sM"%self.total_size,"utf8"))
  75. except Exception as ex:
  76. self.conn.send(bytes(ex,"utf8"))
  77. else:
  78. self.conn.send(bytes("请上传文件,文件不能为空","utf8"))
  79. def get(self):
  80. '''
  81. 下载文件
  82. :return:
  83. '''
  84. if self.cmd_file:
  85. os.chdir(self.home) # 进入用户根目录
  86. self.file = os.getcwd()+"\\"+ self.cmd_file
  87. if os.path.isfile(self.file):
  88. f = open(self.file, 'rb')
  89. self.fsize = os.path.getsize(self.file) # 获取要发送文件的大小
  90. self.conn.send(bytes("f_ack_read","utf8"))
  91. self.conn.recv(1000)
  92. print("需发送文件大小:",self.fsize)
  93. self.conn.send(bytes("fsize|%s"%self.fsize,"utf8")) # 发送文件大小及要发送准备完毕指令
  94. if self.conn.recv(1000).decode() == "f_ack": # 接收对方是否准备就绪
  95. self.fsize = int(self.fsize)
  96. self.size = 0
  97. ack =""
  98. while self.size < self.fsize and ack !="ok":
  99. data = f.read(self.fsize) # 一次读取分片大小4096
  100. self.conn.send(data)
  101. self.size += len(data)
  102. print("实际发送文件大小:",self.size)
  103. ack = self.conn.recv(1000).decode() # 接收客户端是否下载完指令
  104. self.conn.send(bytes("成功","utf8"))
  105. else:
  106. self.conn.send(bytes("接收失败","utf8"))
  107. else:
  108. self.conn.send(bytes("文件不存在","utf8"))
  109. else:
  110. self.conn.send(bytes("请输入文件名","utf8"))
  111. def dir(self):
  112. '''
  113. 查看文件
  114. :return:
  115. '''
  116. self.current_space =int(self.getdirsize(self.home))
  117. # 文件列表
  118. self.li = ""
  119. # 目录列表
  120. self.dl = ""
  121. try:
  122. os.chdir(self.home)
  123. except:
  124. os.makedirs(self.home)
  125. os.chdir(self.home)
  126. try:
  127. if os.listdir(os.getcwd()):
  128. for self.i in os.listdir(os.getcwd()):
  129. self.file = os.getcwd()+'\\'+self.i
  130. if os.path.isfile(self.file):
  131. # 获取文件大小
  132. self.fsize = int(os.path.getsize(self.file)/1024)
  133. if self.fsize < 1:
  134. self.fsize = 4
  135. else:
  136. self.fsize +=4
  137. self.li += '%s -rw-rw-rw- 占用大小:%skb\r\n'% (self.i,self.fsize)
  138. else:
  139. self.dl += '%s\r\n'%self.i
  140. self.conn.send(bytes("目录:\r\n\r\n%s 文件:\r\n%s\r\n \r\n当前目录空间大小:%skb"%(self.dl,self.li,self.current_space),"utf8"))
  141. else:
  142. self.conn.send(bytes("当前目录为:%s"%(self.home),"utf8"))
  143. except Exception as ex:
  144. self.conn.send(bytes(ex,"utf8"))
  145. def cd(self):
  146. '''
  147. 进入目录
  148. :return:
  149. '''
  150. if self.cmd_file:
  151. os.chdir(self.home) # 先进入到工作目录
  152. self.dir_change = os.path.abspath(os.path.join(self.home,"%s\%s"%(self.home,self.cmd_file)))
  153. if self.root in self.dir_change:
  154. try:
  155. os.chdir(self.dir_change)
  156. self.home = self.dir_change
  157. self.conn.send(bytes("当前工作目录为:%s"%self.home,"utf8"))
  158. except:
  159. os.makedirs(self.dir_change)
  160. os.chdir(self.dir_change)
  161. self.home = self.dir_change
  162. self.conn.send(bytes("当前工作目录为:%s"%self.home,"utf8"))
  163. else:
  164. self.conn.send(bytes("当前工作目录为:%s 更改失败!"%self.home,"utf8"))
  165. else:
  166. os.chdir(self.home)
  167. self.conn.send(bytes("当前工作目录为:%s"%self.home,"utf8"))
  168. def mkd(self):
  169. '''
  170. 创建目录
  171. :return:
  172. '''
  173. if self.cmd_file:
  174. try:
  175. os.makedirs(self.cmd_file)
  176. self.conn.send(bytes("创建目录成功!","utf8"))
  177. except Exception as ex:
  178. self.conn.send(bytes("创建目录失败!原因:%s"%ex,"utf8"))
  179. else:
  180. self.conn.send(bytes("请输入文件夹名!","utf8"))
  181. def delete(self):
  182. '''
  183. 删除文件
  184. :return:
  185. '''
  186. os.chdir(self.home) # 进入用户根目录
  187. try:
  188. self.file = self.home+'\\'+ self.cmd_file
  189. if os.path.isfile(self.file):
  190. os.remove(self.cmd_file)
  191. self.conn.send(bytes("文件:%s删除成功!"%self.cmd_file,"utf8"))
  192. else:
  193. os.removedirs(self.cmd_file)
  194. self.conn.send(bytes("目录删除成功!","utf8"))
  195. os.chdir(self.root)
  196. except Exception:
  197. if os.path.isdir(self.root):
  198. self.conn.send(bytes("删除失败!","utf8"))
  199. else:
  200. os.makedirs(self.root)
  201. self.conn.send(bytes("删除失败!","utf8"))
  202. def help(self):
  203. '''
  204. FTP帮助信息
  205. :return:
  206. '''
  207. self.conn.send(bytes("""
  208. FTP服务器操作方法有: put------>上传文件至服务器
  209. get------>从服务器上下载文件
  210. dir------>查看服务器文件列表
  211. cd------->进入指定文件夹
  212. delete--->删除文件
  213. mkd ----->创建目录
  214. help----->帮助信息
  215. q ------->退出
  216. ""","utf8"))
  217. def run(self):
  218. while True:
  219. # try:
  220. # # 接收客户端发来的命令信息
  221. self.cmd = self.conn.recv(1000)
  222. self.cmd_action = str(self.cmd.decode())
  223. # 判断命令是否含有空格
  224. self.fg = re.search("\s","%s"%self.cmd_action)
  225. if self.fg:
  226. self.cmd_action,self.cmd_file = str(self.cmd_action).split(" ")
  227. else:
  228. self.cmd_file =None
  229. # print("cmd_action:",self.cmd_action,"cmd_file:",self.cmd_file)
  230. if hasattr(FTPs,self.cmd_action):
  231. func = getattr(self,self.cmd_action)
  232. func()
  233. continue
  234. else:
  235. self.conn.send(b'command is not found!')
  236. continue
  237. # except Exception as ex:
  238. # print("系统异常:%s"%ex)

客户端:

main.py

  1. #!/usr/bin/env python3.5
  2. # -*-coding:utf8-*-
  3. import sys,os,re
  4. import socket,hashlib
  5. BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  6. sys.path.append(BASEDIR)
  7. from core import file_handler
  8. from conf import setting
  9. def login():
  10. hash = hashlib.sha512()
  11. while True:
  12. user_input = input("请输入用户名:").strip()
  13. pass_input = input("请输入密码:").strip()
  14. if len(user_input) !=0 and len(pass_input) != 0:
  15. hash.update(bytes(pass_input,"utf8"))
  16. sha_pwd = hash.hexdigest()
  17. user = "%s|%s"% (user_input,sha_pwd)
  18. return user
  19. break
  20. def ftp_client():
  21. sk = socket.socket()
  22. sk.connect((setting.IP_PORT["host"],setting.IP_PORT["port"]))
  23. while True:
  24. flage = False
  25. sk.send(bytes("connect","utf8"))
  26. msg = sk.recv(100)
  27. print("欢迎访问FTP服务器,请根据提示进行操作")
  28. if msg.decode() == "login":
  29. while flage == False:
  30. login_user =login()
  31. username,password = str(login_user).split("|")
  32. sk.send(bytes(login_user,"utf8"))
  33. user_info = sk.recv(1000)
  34. if user_info.decode() == "login_ack":
  35. print("登陆成功!")
  36. flage = True
  37. break
  38. print(user_info.decode())
  39. while flage:
  40. cmd_action = input("请输入操作命令如:get fy.py or help :").strip()
  41. if len(cmd_action) == 0:continue
  42. if cmd_action == "q":
  43. sys.exit()
  44. # 判断命令是否含有空格
  45. fg = re.search("\s","%s"%cmd_action)
  46. if fg:
  47. cmd,cmd_file = str(cmd_action).split(" ")
  48. ftp = file_handler.ftpc(sk,username,cmd_action,setting.DATABASE["local"])
  49. if hasattr(ftp,cmd):
  50. func = getattr(ftp,cmd)
  51. func()
  52. continue
  53. else:
  54. cmd_file =None
  55. sk.send(bytes(cmd_action,"utf8"))
  56. rec_msg = sk.recv(8000)
  57. print(rec_msg.decode())
  58. if flage == "False":
  59. sk.send(bytes("connect","utf8"))
  60. sk.close()
  61. def run():
  62. ftp_client()
  63. if __name__ == "__main__":
  64. run()

file_handler.py:

  1. #!/usr/bin/env python3.5
  2. # -*-coding:utf8-*-
  3. import sys,os,re
  4. import socket
  5. BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  6. sys.path.append(BASEDIR)
  7. class ftpc(object):
  8. def __init__(self,sk,username,cmd_action,home):
  9. self.sk = sk
  10. self.username = username
  11. self.cmd_action = cmd_action
  12. self.home = home
  13. def put(self):
  14. '''
  15. 上传文件
  16. :return:
  17. '''
  18. try:
  19. os.chdir(self.home)
  20. except:
  21. os.makedirs(self.home)
  22. os.chdir(self.home)
  23. # 判断命令是否含有空格
  24. fg = re.search("\s","%s"%self.cmd_action)
  25. if fg:
  26. self.cmd,self.cmd_file = str(self.cmd_action).split(" ")
  27. if os.path.isfile(os.getcwd()+"\\"+self.cmd_file):
  28. self.sk.send(bytes(self.cmd_action,"utf8")) # 发送动作命令
  29. rec_msg = self.sk.recv(8000)
  30. if rec_msg.decode() == "f_ack":
  31. f = open(self.cmd_file, 'rb')
  32. self.fsize = os.path.getsize(self.cmd_file) # 获取要发送文件的大小
  33. self.sk.send(bytes("fsize|%s"%self.fsize,"utf8")) # 发送文件大小
  34. self.ack = self.sk.recv(1000)
  35. if self.ack.decode() =="f_ack_ready":
  36. self.fsize = int(self.fsize)
  37. self.size = 0
  38. ack =""
  39. while self.size < self.fsize and ack !="ok":
  40. data = f.read(4095) # 一次读取分片大小4095
  41. self.sk.send(data)
  42. self.size += len(data)
  43. count = int(self.size/self.fsize*100)
  44. print('#'*count,"->",(count),"%")
  45. ack = self.sk.recv(1000).decode()
  46. if ack =="ok":
  47. print("上传成功")
  48. else:
  49. print("上传失败")
  50. else:
  51. print(self.ack.decode())
  52. else:
  53. print("上传文件失败:%s"%rec_msg.decode())
  54. else:
  55. print("上传文件失败,请输入正确的文件名!")
  56. else:
  57. print("上传文件失败,请输入正确的文件名!")
  58. def get(self):
  59. '''
  60. 下载文件
  61. :return:
  62. '''
  63. try:
  64. os.chdir(self.home)
  65. except:
  66. os.makedirs(self.home)
  67. os.chdir(self.home)
  68. # 判断命令是否含有空格
  69. fg = re.search("\s","%s"%self.cmd_action)
  70. if fg:
  71. self.cmd,self.cmd_file = str(self.cmd_action).split(" ")
  72. else:
  73. self.cmd_file =None
  74. self.sk.send(bytes(self.cmd_action,"utf8"))
  75. rec_msg = self.sk.recv(8000)
  76. if rec_msg.decode() == "f_ack_read":
  77. self.rec = self.sk.send(bytes("ok","utf8"))
  78. self.rec_size = self.sk.recv(2048)
  79. self.ack_rec= str(self.rec_size.decode()).split("|")
  80. self.sk.send(bytes("f_ack","utf8"))
  81. self.ack_s =int(self.ack_rec[1])
  82. print(self.ack_s)
  83. self.re_s = 0
  84. f = open(self.cmd_file,"wb")
  85. while self.re_s < self.ack_s:
  86. xx = self.re_s/self.ack_s*100
  87. data = self.sk.recv(4096)
  88. self.re_s += len(data)
  89. # print(data.decode("gbk"))
  90. f.write(data)
  91. count = int(xx)
  92. print('#'*count,"->",(count+1),"%")
  93. self.sk.send(bytes("ok","utf8"))
  94. print(self.re_s)
  95. self.ack_ok = self.sk.recv(1024)
  96. print("接收文件:%s"%self.ack_ok.decode())
  97. else:
  98. print("接收文件失败:%s"%rec_msg.decode())

如下是重要模块进行收藏:

OS模块

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')   删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息
os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    输出用于分割文件路径的字符串
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  运行shell命令,直接显示
os.environ  获取系统环境变量
os.path.abspath(path)  返回path规范化的绝对路径
os.path.split(path)  将path分割成目录和文件名二元组返回
os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间

sys模块

sys.argv           命令行参数List,第一个元素是程序本身路径
sys.exit(n)        退出程序,正常退出时exit(0)
sys.version        获取Python解释程序的版本信息
sys.maxint         最大的Int值
sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform       返回操作系统平台名称

?

1

2

sys.stdout.write('please:')

val = sys.stdin.readline()[:-1]

re 模块

匹配格式

 

模式描述
^匹配字符串的开头
$匹配字符串的末尾。
.匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[...]用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k
[^...]不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re*匹配0个或多个的表达式。
re+匹配1个或多个的表达式。
re?匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n}
re{ n,}精确匹配n个前面表达式。
re{ n, m}匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b匹配a或b
(re)G匹配括号内的表达式,也表示一个组
(?imx)正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx)正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re)类似 (...), 但是不表示一个组
(?imx: re)在括号中使用i, m, 或 x 可选标志
(?-imx: re)在括号中不使用i, m, 或 x 可选标志
(?#...)注释.
(?= re)前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re)前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?> re)匹配的独立模式,省去回溯。
\w匹配字母数字
\W匹配非字母数字
\s匹配任意空白字符,等价于 [\t\n\r\f].
\S匹配任意非空字符
\d匹配任意数字,等价于 [0-9].
\D匹配任意非数字
\A匹配字符串开始
\Z匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
\z匹配字符串结束
\G匹配最后匹配完成的位置。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\n, \t, 等.匹配一个换行符。匹配一个制表符。等
\1...\9匹配第n个分组的子表达式。
\10匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。

 

正则表达式常用5种操作

re.match(pattern, string) # 从头匹配
re.search(pattern, string) # 匹配整个字符串,直到找到一个匹配
re.split() # 将匹配到的格式当做分割点对字符串分割成列表

?

1

2

>>>m = re.split("[0-9]", "alex1rain2jack3helen rachel8")

>>>print(m)

输出:['alex', 'rain', 'jack', 'helen rachel', '']

re.findall() # 找到所有要匹配的字符并返回列表格式

?

1

2

>>>m = re.findall("[0-9]", "alex1rain2jack3helen rachel8")

>>>print(m)

输出:['1', '2', '3', '8']

re.sub(pattern, repl, string, count,flag) # 替换匹配到的字符

?

1

2

m=re.sub("[0-9]","|", "alex1rain2jack3helen rachel8",count=2 )

print(m)

输出:alex|rain|jack3helen rachel8

正则表达式实例

字符匹配

 

实例描述
python匹配 "python".

 

字符类

 

实例描述
[Pp]ython匹配 "Python" 或 "python
rub[ye]匹配 "ruby" 或 "rube
[aeiou]匹配中括号内的任意一个字母
[0-9]匹配任何数字。类似于 [0123456789]
[a-z]匹配任何小写字母
[A-Z]匹配任何大写字母
[a-zA-Z0-9]匹配任何字母及数字
[^aeiou]除了aeiou字母以外的所有字符
[^0-9]匹配除了数字外的字符

 

特殊字符类

 

实例描述
.匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
\d匹配一个数字字符。等价于 [0-9]。
\D匹配一个非数字字符。等价于 [^0-9]。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

 

re.match与re.search的区别

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

PS:这里再为大家提供2款非常方便的正则表达式工具供大家参考使用:

JavaScript正则表达式在线测试工具:
http://tools.jb51.net/regex/javascript

正则表达式在线生成工具:
http://tools.jb51.net/regex/create_reg

更多关于Python相关内容可查看本站专题:《Python正则表达式用法总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/216952
推荐阅读
相关标签
  

闽ICP备14008679号