Python實(shí)現(xiàn)基于多線程、多用戶的FTP服務(wù)器與客戶端功能完整實(shí)例
本文實(shí)例講述了Python實(shí)現(xiàn)基于多線程、多用戶的FTP服務(wù)器與客戶端功能。分享給大家供大家參考,具體如下:
項(xiàng)目介紹:
1. 用戶加密認(rèn)證
2. 允許同時(shí)多用戶登錄
3. 每個用戶有自己的家目錄 ,且只能訪問自己的家目錄
4. 對用戶進(jìn)行磁盤配額,每個用戶的可用空間不同
5. 允許用戶在ftp server上隨意切換目錄
6. 允許用戶查看當(dāng)前目錄下文件
7. 允許上傳和下載文件,保證文件一致性
8. 文件傳輸過程中顯示進(jìn)度條
實(shí)現(xiàn)的原理:
服務(wù)器端啟用端口監(jiān)聽,并對每一連接啟用一個線程,對用戶登陸密碼采用SHA512進(jìn)行加密并進(jìn)行匹配,當(dāng)用戶登陸成功后,實(shí)例化FTPS,并引導(dǎo)客戶端進(jìn)入主命令模式,
然后實(shí)現(xiàn)FTP的上傳功能、下載功能、新建目錄、刪除文件或目錄、切換目錄等實(shí)例化操作,同時(shí)對相關(guān)上傳下載進(jìn)行進(jìn)度條顯示,服務(wù)器端顯示下載或上傳文件的大小等
客戶端與服務(wù)器協(xié)商建立連接后,進(jìn)行用戶身份登陸,登陸成功接收服務(wù)器指令,轉(zhuǎn)入命令輸入窗口,同時(shí)對put 與 get命令進(jìn)行判斷,實(shí)現(xiàn)特定的上傳與下載功能
核心代碼實(shí)現(xiàn)如下:
服務(wù)器端
main.py
#!/usr/bin/env python3.5 # -*-coding:utf8-*- import os,sys,socket,pickle BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASEDIR) from conf import setting from core import file_handler from core import db_handler import select,hashlib import threading def login(username,password): """ FTP登陸驗(yàn)證函數(shù) :param username: :param password: :return: # testDict ={"username":"jjb","password":"123456","file_dir":"E:\python","file_size":500} # file = 'jjb.pkl' # fp = open(file,'wb') # pickle.dump(testDict,fp) # fp.close() f = open("jjb.pkl","rb") data = pickle.loads(f.read()) f.close() print(data) """ #實(shí)例化加密函數(shù) hash = hashlib.sha512() db= db_handler.handler(setting.DATABASE,username) if os.path.isfile(db): f = open(db,"rb") data = pickle.loads(f.read()) f.close() if username == data["name"]: hash.update(bytes(data["password"],"utf8")) hash_pwd = hash.hexdigest() if hash_pwd == password: filedir = data["file_dir"] filesize = data["file_size"] return "True|%s|%s"%(filedir,filesize) else: return "False||" else: return "False||" else: return "False||" def process(conn,addr): flage = "False" # 接收客戶端連接請求信息 info = conn.recv(1000) if info.decode() == "connect": conn.send(bytes("login","utf8")) # 接收用戶及密碼信息 while flage =="False": user_check =conn.recv(8000) # 分割用戶名及密碼 username,password = str(user_check.decode()).split("|") # 調(diào)用登陸驗(yàn)證函數(shù) login_ack = login(username,password) flage,home,size = str(login_ack).split("|") # print(flage,home,size) # print("user_input:",username,"user_pass:",password) if flage =="True": # 登陸成功發(fā)送登陸確認(rèn)信息給客戶端 conn.send(bytes("login_ack","utf8")) # 實(shí)例化FTPserver ftp = file_handler.FTPs(username,conn,home,size) # 登陸用戶,數(shù)據(jù)連接,工作目錄,磁盤配額 ftp.run() break else: # 登陸失敗,發(fā)送給客戶端重新驗(yàn)證 conn.send(bytes("登陸失??!","utf8")) def ftp_server(): ''' 啟動FTP服務(wù)器端,開啟線程監(jiān)聽 :return: ''' server = socket.socket() server.bind((setting.IP_PORT["host"],setting.IP_PORT["port"])) server.listen(10) while True: r,w,e = select.select([server,], [], [], 1) for i,server in enumerate(r): conn,addr = server.accept() # 創(chuàng)建線程 t = threading.Thread(target=process, args=(conn, addr)) # 啟動線程 t.start() server.close() def run(): ftp_server() if __name__ =="__main__": run()
file_handler.py:
#!/usr/bin/env python3.5 # -*-coding:utf8-*- import os,sys BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASEDIR) import re from core import db_handler from conf import setting import pickle class FTPs(object): ''' ftp操作命令方法: ''' def __init__(self,username,conn,home,total_size): ''' 初始化參數(shù) :param username: 操作用戶名 :param conn: sock連接 :param home: 用戶根目錄 :param total_size: 磁盤配額 :return: ''' self.username = username self.conn = conn self.root = home self.home = self.root self.total_size = int(total_size) self.cmd_file = None # 文件指令 self.psize = 4096 # 文件分片 def getdirsize(self,space): ''' 計(jì)算磁盤空間大小 :return: ''' self.dirsize = 0 for root,dirs,files in os.walk(space): self.dirsize += (sum([os.path.getsize(os.path.join(root,name))for name in files])/1024) return int(self.dirsize) def put(self): ''' 上傳文件 :return: ''' if self.cmd_file: self.user_space = int(self.getdirsize(self.root)/1024) # 組合接收字符串 self.file_root = '%s\\%s'% (self.home,self.cmd_file) # # 獲取文件名 self.f =os.path.basename(self.file_root) if os.path.isdir(self.home): os.chdir(self.home) else: os.makedirs(self.home) os.chdir(self.home) try: self.conn.send(bytes("f_ack","utf8")) self.size = str(self.conn.recv(1024).decode()).split("|") if self.size[0]== "fsize": self.fss = int(self.size[1]) self.f_total_size = int(self.user_space + (self.fss/1024/1024)) if self.f_total_size < self.total_size: # 判斷空間是否超額 self.conn.send(bytes("f_ack_ready","utf8")) self.bsize = 0 print("需要上傳文件大?。?,self.fss) # 打開文件 f=open(self.f,'wb') while self.bsize < self.fss: data = self.conn.recv(self.psize) self.bsize += len(data) f.write(data) self.conn.send(bytes("ok","utf8")) print("實(shí)際已上傳文件大?。?,self.bsize) else: self.conn.send(bytes("上傳空間不足!無法上傳,你當(dāng)前磁盤配額為%sM"%self.total_size,"utf8")) except Exception as ex: self.conn.send(bytes(ex,"utf8")) else: self.conn.send(bytes("請上傳文件,文件不能為空","utf8")) def get(self): ''' 下載文件 :return: ''' if self.cmd_file: os.chdir(self.home) # 進(jìn)入用戶根目錄 self.file = os.getcwd()+"\\"+ self.cmd_file if os.path.isfile(self.file): f = open(self.file, 'rb') self.fsize = os.path.getsize(self.file) # 獲取要發(fā)送文件的大小 self.conn.send(bytes("f_ack_read","utf8")) self.conn.recv(1000) print("需發(fā)送文件大?。?,self.fsize) self.conn.send(bytes("fsize|%s"%self.fsize,"utf8")) # 發(fā)送文件大小及要發(fā)送準(zhǔn)備完畢指令 if self.conn.recv(1000).decode() == "f_ack": # 接收對方是否準(zhǔn)備就緒 self.fsize = int(self.fsize) self.size = 0 ack ="" while self.size < self.fsize and ack !="ok": data = f.read(self.fsize) # 一次讀取分片大小4096 self.conn.send(data) self.size += len(data) print("實(shí)際發(fā)送文件大?。?,self.size) ack = self.conn.recv(1000).decode() # 接收客戶端是否下載完指令 self.conn.send(bytes("成功","utf8")) else: self.conn.send(bytes("接收失敗","utf8")) else: self.conn.send(bytes("文件不存在","utf8")) else: self.conn.send(bytes("請輸入文件名","utf8")) def dir(self): ''' 查看文件 :return: ''' self.current_space =int(self.getdirsize(self.home)) # 文件列表 self.li = "" # 目錄列表 self.dl = "" try: os.chdir(self.home) except: os.makedirs(self.home) os.chdir(self.home) try: if os.listdir(os.getcwd()): for self.i in os.listdir(os.getcwd()): self.file = os.getcwd()+'\\'+self.i if os.path.isfile(self.file): # 獲取文件大小 self.fsize = int(os.path.getsize(self.file)/1024) if self.fsize < 1: self.fsize = 4 else: self.fsize +=4 self.li += '%s -rw-rw-rw- 占用大小:%skb\r\n'% (self.i,self.fsize) else: self.dl += '%s\r\n'%self.i self.conn.send(bytes("目錄:\r\n\r\n%s 文件:\r\n%s\r\n \r\n當(dāng)前目錄空間大?。?skb"%(self.dl,self.li,self.current_space),"utf8")) else: self.conn.send(bytes("當(dāng)前目錄為:%s"%(self.home),"utf8")) except Exception as ex: self.conn.send(bytes(ex,"utf8")) def cd(self): ''' 進(jìn)入目錄 :return: ''' if self.cmd_file: os.chdir(self.home) # 先進(jìn)入到工作目錄 self.dir_change = os.path.abspath(os.path.join(self.home,"%s\%s"%(self.home,self.cmd_file))) if self.root in self.dir_change: try: os.chdir(self.dir_change) self.home = self.dir_change self.conn.send(bytes("當(dāng)前工作目錄為:%s"%self.home,"utf8")) except: os.makedirs(self.dir_change) os.chdir(self.dir_change) self.home = self.dir_change self.conn.send(bytes("當(dāng)前工作目錄為:%s"%self.home,"utf8")) else: self.conn.send(bytes("當(dāng)前工作目錄為:%s 更改失敗!"%self.home,"utf8")) else: os.chdir(self.home) self.conn.send(bytes("當(dāng)前工作目錄為:%s"%self.home,"utf8")) def mkd(self): ''' 創(chuàng)建目錄 :return: ''' if self.cmd_file: try: os.makedirs(self.cmd_file) self.conn.send(bytes("創(chuàng)建目錄成功!","utf8")) except Exception as ex: self.conn.send(bytes("創(chuàng)建目錄失敗!原因:%s"%ex,"utf8")) else: self.conn.send(bytes("請輸入文件夾名!","utf8")) def delete(self): ''' 刪除文件 :return: ''' os.chdir(self.home) # 進(jìn)入用戶根目錄 try: self.file = self.home+'\\'+ self.cmd_file if os.path.isfile(self.file): os.remove(self.cmd_file) self.conn.send(bytes("文件:%s刪除成功!"%self.cmd_file,"utf8")) else: os.removedirs(self.cmd_file) self.conn.send(bytes("目錄刪除成功!","utf8")) os.chdir(self.root) except Exception: if os.path.isdir(self.root): self.conn.send(bytes("刪除失?。?,"utf8")) else: os.makedirs(self.root) self.conn.send(bytes("刪除失??!","utf8")) def help(self): ''' FTP幫助信息 :return: ''' self.conn.send(bytes(""" FTP服務(wù)器操作方法有: put------>上傳文件至服務(wù)器 get------>從服務(wù)器上下載文件 dir------>查看服務(wù)器文件列表 cd------->進(jìn)入指定文件夾 delete--->刪除文件 mkd ----->創(chuàng)建目錄 help----->幫助信息 q ------->退出 ""","utf8")) def run(self): while True: # try: # # 接收客戶端發(fā)來的命令信息 self.cmd = self.conn.recv(1000) self.cmd_action = str(self.cmd.decode()) # 判斷命令是否含有空格 self.fg = re.search("\s","%s"%self.cmd_action) if self.fg: self.cmd_action,self.cmd_file = str(self.cmd_action).split(" ") else: self.cmd_file =None # print("cmd_action:",self.cmd_action,"cmd_file:",self.cmd_file) if hasattr(FTPs,self.cmd_action): func = getattr(self,self.cmd_action) func() continue else: self.conn.send(b'command is not found!') continue # except Exception as ex: # print("系統(tǒng)異常:%s"%ex)
客戶端
client.py:
#!/usr/bin/env python3.5 # -*-coding:utf8-*- import sys,os,re import socket,hashlib BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASEDIR) from core import file_handler from conf import setting def login(): hash = hashlib.sha512() while True: user_input = input("請輸入用戶名:").strip() pass_input = input("請輸入密碼:").strip() if len(user_input) !=0 and len(pass_input) != 0: hash.update(bytes(pass_input,"utf8")) sha_pwd = hash.hexdigest() user = "%s|%s"% (user_input,sha_pwd) return user break def ftp_client(): sk = socket.socket() sk.connect((setting.IP_PORT["host"],setting.IP_PORT["port"])) while True: flage = False sk.send(bytes("connect","utf8")) msg = sk.recv(100) print("歡迎訪問FTP服務(wù)器,請根據(jù)提示進(jìn)行操作") if msg.decode() == "login": while flage == False: login_user =login() username,password = str(login_user).split("|") sk.send(bytes(login_user,"utf8")) user_info = sk.recv(1000) if user_info.decode() == "login_ack": print("登陸成功!") flage = True break print(user_info.decode()) while flage: cmd_action = input("請輸入操作命令如:get fy.py or help :").strip() if len(cmd_action) == 0:continue if cmd_action == "q": sys.exit() # 判斷命令是否含有空格 fg = re.search("\s","%s"%cmd_action) if fg: cmd,cmd_file = str(cmd_action).split(" ") ftp = file_handler.ftpc(sk,username,cmd_action,setting.DATABASE["local"]) if hasattr(ftp,cmd): func = getattr(ftp,cmd) func() continue else: cmd_file =None sk.send(bytes(cmd_action,"utf8")) rec_msg = sk.recv(8000) print(rec_msg.decode()) if flage == "False": sk.send(bytes("connect","utf8")) sk.close() def run(): ftp_client() if __name__ == "__main__": run()
file_handler.py:
#!/usr/bin/env python3.5 # -*-coding:utf8-*- import sys,os,re import socket BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(BASEDIR) class ftpc(object): def __init__(self,sk,username,cmd_action,home): self.sk = sk self.username = username self.cmd_action = cmd_action self.home = home def put(self): ''' 上傳文件 :return: ''' try: os.chdir(self.home) except: os.makedirs(self.home) os.chdir(self.home) # 判斷命令是否含有空格 fg = re.search("\s","%s"%self.cmd_action) if fg: self.cmd,self.cmd_file = str(self.cmd_action).split(" ") if os.path.isfile(os.getcwd()+"\\"+self.cmd_file): self.sk.send(bytes(self.cmd_action,"utf8")) # 發(fā)送動作命令 rec_msg = self.sk.recv(8000) if rec_msg.decode() == "f_ack": f = open(self.cmd_file, 'rb') self.fsize = os.path.getsize(self.cmd_file) # 獲取要發(fā)送文件的大小 self.sk.send(bytes("fsize|%s"%self.fsize,"utf8")) # 發(fā)送文件大小 self.ack = self.sk.recv(1000) if self.ack.decode() =="f_ack_ready": self.fsize = int(self.fsize) self.size = 0 ack ="" while self.size < self.fsize and ack !="ok": data = f.read(4095) # 一次讀取分片大小4095 self.sk.send(data) self.size += len(data) count = int(self.size/self.fsize*100) print('#'*count,"->",(count),"%") ack = self.sk.recv(1000).decode() if ack =="ok": print("上傳成功") else: print("上傳失敗") else: print(self.ack.decode()) else: print("上傳文件失敗:%s"%rec_msg.decode()) else: print("上傳文件失敗,請輸入正確的文件名!") else: print("上傳文件失敗,請輸入正確的文件名!") def get(self): ''' 下載文件 :return: ''' try: os.chdir(self.home) except: os.makedirs(self.home) os.chdir(self.home) # 判斷命令是否含有空格 fg = re.search("\s","%s"%self.cmd_action) if fg: self.cmd,self.cmd_file = str(self.cmd_action).split(" ") else: self.cmd_file =None self.sk.send(bytes(self.cmd_action,"utf8")) rec_msg = self.sk.recv(8000) if rec_msg.decode() == "f_ack_read": self.rec = self.sk.send(bytes("ok","utf8")) self.rec_size = self.sk.recv(2048) self.ack_rec= str(self.rec_size.decode()).split("|") self.sk.send(bytes("f_ack","utf8")) self.ack_s =int(self.ack_rec[1]) print(self.ack_s) self.re_s = 0 f = open(self.cmd_file,"wb") while self.re_s < self.ack_s: xx = self.re_s/self.ack_s*100 data = self.sk.recv(4096) self.re_s += len(data) # print(data.decode("gbk")) f.write(data) count = int(xx) print('#'*count,"->",(count+1),"%") self.sk.send(bytes("ok","utf8")) print(self.re_s) self.ack_ok = self.sk.recv(1024) print("接收文件:%s"%self.ack_ok.decode()) else: print("接收文件失?。?s"%rec_msg.decode())
如下是重要模塊進(jìn)行收藏:
OS模塊
os.getcwd()
獲取當(dāng)前工作目錄,即當(dāng)前python腳本工作的目錄路徑
os.chdir("dirname")
改變當(dāng)前腳本工作目錄;相當(dāng)于shell下cd
os.curdir
返回當(dāng)前目錄: ('.')
os.pardir
獲取當(dāng)前目錄的父目錄字符串名:('..')
os.makedirs('dirname1/dirname2')
可生成多層遞歸目錄
os.removedirs('dirname1')
若目錄為空,則刪除,并遞歸到上一級目錄,如若也為空,則刪除,依此類推
os.mkdir('dirname')
生成單級目錄;相當(dāng)于shell中mkdir dirname
os.rmdir('dirname')
刪除單級空目錄,若目錄不為空則無法刪除,報(bào)錯;相當(dāng)于shell中rmdir dirname
os.listdir('dirname')
列出指定目錄下的所有文件和子目錄,包括隱藏文件,并以列表方式打印
os.remove()
刪除一個文件
os.rename("oldname","newname")
重命名文件/目錄
os.stat('path/filename')
獲取文件/目錄信息
os.sep
輸出操作系統(tǒng)特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep
輸出當(dāng)前平臺使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep
輸出用于分割文件路徑的字符串
os.name
輸出字符串指示當(dāng)前使用平臺。win->'nt'; Linux->'posix'
os.system("bash command")
運(yùn)行shell命令,直接顯示
os.environ
獲取系統(tǒng)環(huán)境變量
os.path.abspath(path)
返回path規(guī)范化的絕對路徑
os.path.split(path)
將path分割成目錄和文件名二元組返回
os.path.dirname(path)
返回path的目錄。其實(shí)就是os.path.split(path)的第一個元素
os.path.basename(path)
返回path最后的文件名。如何path以/或\結(jié)尾,那么就會返回空值。即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[, ...]])
將多個路徑組合后返回,第一個絕對路徑之前的參數(shù)將被忽略
os.path.getatime(path)
返回path所指向的文件或者目錄的最后存取時(shí)間
os.path.getmtime(path)
返回path所指向的文件或者目錄的最后修改時(shí)間
sys模塊
sys.argv
命令行參數(shù)List,第一個元素是程序本身路徑
sys.exit(n)
退出程序,正常退出時(shí)exit(0)
sys.version
獲取Python解釋程序的版本信息
sys.maxint
最大的Int值
sys.path
返回模塊的搜索路徑,初始化時(shí)使用PYTHONPATH環(huán)境變量的值
sys.platform
返回操作系統(tǒng)平臺名稱
sys.stdout.write('please:') val = sys.stdin.readline()[:-1]
re 模塊
匹配格式
模式 | 描述 |
---|---|
^ | 匹配字符串的開頭 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了換行符,當(dāng)re.DOTALL標(biāo)記被指定時(shí),則可以匹配包括換行符的任意字符。 |
[...] | 用來表示一組字符,單獨(dú)列出:[amk] 匹配 'a','m'或'k |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0個或多個的表達(dá)式。 |
re+ | 匹配1個或多個的表達(dá)式。 |
re? | 匹配0個或1個由前面的正則表達(dá)式定義的片段,非貪婪方式 |
re{ n} | |
re{ n,} | 精確匹配n個前面表達(dá)式。 |
re{ n, m} | 匹配 n 到 m 次由前面的正則表達(dá)式定義的片段,貪婪方式 |
a| b | 匹配a或b |
(re) | G匹配括號內(nèi)的表達(dá)式,也表示一個組 |
(?imx) | 正則表達(dá)式包含三種可選標(biāo)志:i, m, 或 x 。只影響括號中的區(qū)域。 |
(?-imx) | 正則表達(dá)式關(guān)閉 i, m, 或 x 可選標(biāo)志。只影響括號中的區(qū)域。 |
(?: re) | 類似 (...), 但是不表示一個組 |
(?imx: re) | 在括號中使用i, m, 或 x 可選標(biāo)志 |
(?-imx: re) | 在括號中不使用i, m, 或 x 可選標(biāo)志 |
(?#...) | 注釋. |
(?= re) | 前向肯定界定符。如果所含正則表達(dá)式,以 ... 表示,在當(dāng)前位置成功匹配時(shí)成功,否則失敗。但一旦所含表達(dá)式已經(jīng)嘗試,匹配引擎根本沒有提高;模式的剩余部分還要嘗試界定符的右邊。 |
(?! re) | 前向否定界定符。與肯定界定符相反;當(dāng)所含表達(dá)式不能在字符串當(dāng)前位置匹配時(shí)成功 |
(?> re) | 匹配的獨(dú)立模式,省去回溯。 |
\w | 匹配字母數(shù)字 |
\W | 匹配非字母數(shù)字 |
\s | 匹配任意空白字符,等價(jià)于 [\t\n\r\f]. |
\S | 匹配任意非空字符 |
\d | 匹配任意數(shù)字,等價(jià)于 [0-9]. |
\D | 匹配任意非數(shù)字 |
\A | 匹配字符串開始 |
\Z | 匹配字符串結(jié)束,如果是存在換行,只匹配到換行前的結(jié)束字符串。c |
\z | 匹配字符串結(jié)束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等. | 匹配一個換行符。匹配一個制表符。等 |
\1...\9 | 匹配第n個分組的子表達(dá)式。 |
\10 | 匹配第n個分組的子表達(dá)式,如果它經(jīng)匹配。否則指的是八進(jìn)制字符碼的表達(dá)式。 |
正則表達(dá)式常用5種操作
re.match(pattern, string)
# 從頭匹配
re.search(pattern, string)
# 匹配整個字符串,直到找到一個匹配
re.split()
# 將匹配到的格式當(dāng)做分割點(diǎn)對字符串分割成列表
>>>m = re.split("[0-9]", "alex1rain2jack3helen rachel8") >>>print(m)
輸出:['alex', 'rain', 'jack', 'helen rachel', '']
re.findall()
# 找到所有要匹配的字符并返回列表格式
>>>m = re.findall("[0-9]", "alex1rain2jack3helen rachel8") >>>print(m)
輸出:['1', '2', '3', '8']
re.sub(pattern, repl, string, count,flag)
# 替換匹配到的字符
m=re.sub("[0-9]","|", "alex1rain2jack3helen rachel8",count=2 ) print(m)
輸出:alex|rain|jack3helen rachel8
正則表達(dá)式實(shí)例
字符匹配
實(shí)例 | 描述 |
---|---|
python | 匹配 "python". |
字符類
實(shí)例 | 描述 |
---|---|
[Pp]ython | 匹配 "Python" 或 "python |
rub[ye] | 匹配 "ruby" 或 "rube |
[aeiou] | 匹配中括號內(nèi)的任意一個字母 |
[0-9] | 匹配任何數(shù)字。類似于 [0123456789] |
[a-z] | 匹配任何小寫字母 |
[A-Z] | 匹配任何大寫字母 |
[a-zA-Z0-9] | 匹配任何字母及數(shù)字 |
[^aeiou] | 除了aeiou字母以外的所有字符 |
[^0-9] | 匹配除了數(shù)字外的字符 |
特殊字符類
實(shí)例 | 描述 |
---|---|
. | 匹配除 "\n" 之外的任何單個字符。要匹配包括 '\n' 在內(nèi)的任何字符,請使用象 '[.\n]' 的模式。 |
\d | 匹配一個數(shù)字字符。等價(jià)于 [0-9]。 |
\D | 匹配一個非數(shù)字字符。等價(jià)于 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價(jià)于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價(jià)于 [^ \f\n\r\t\v]。 |
\w | 匹配包括下劃線的任何單詞字符。等價(jià)于'[A-Za-z0-9_]'。 |
\W | 匹配任何非單詞字符。等價(jià)于 '[^A-Za-z0-9_]'。 |
re.match與re.search的區(qū)別
re.match只匹配字符串的開始,如果字符串開始不符合正則表達(dá)式,則匹配失敗,函數(shù)返回None;而re.search匹配整個字符串,直到找到一個匹配。
PS:這里再為大家提供2款非常方便的正則表達(dá)式工具供大家參考使用:
JavaScript正則表達(dá)式在線測試工具:
http://tools.jb51.net/regex/javascript
正則表達(dá)式在線生成工具:
http://tools.jb51.net/regex/create_reg
更多關(guān)于Python相關(guān)內(nèi)容可查看本站專題:《Python正則表達(dá)式用法總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進(jìn)階經(jīng)典教程》及《Python文件與目錄操作技巧匯總》
希望本文所述對大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
python入門語句基礎(chǔ)之if語句、while語句
本文介紹了python入門語句基礎(chǔ)之if語句、while語句,if?語句讓你能夠檢查程序的當(dāng)前狀態(tài),并據(jù)此采取相應(yīng)的措施,而for?循環(huán)用于針對集合中的每個元素都一個代碼塊,而?while?循環(huán)不斷地運(yùn)行,直到指定的條件不滿足為止,本文通過示例代碼詳解介紹,需要的朋友參考下吧2022-04-04django與小程序?qū)崿F(xiàn)登錄驗(yàn)證功能的示例代碼
這篇文章主要介紹了django與小程序?qū)崿F(xiàn)登錄驗(yàn)證功能的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02OpenCV基于ORB算法實(shí)現(xiàn)角點(diǎn)檢測
這篇文章主要為大家詳細(xì)介紹了OpenCV基于ORB算法實(shí)現(xiàn)角點(diǎn)檢測,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Python實(shí)現(xiàn)自定義讀寫分離代碼實(shí)例
這篇文章主要介紹了Python實(shí)現(xiàn)自定義讀寫分離代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11python實(shí)現(xiàn)按關(guān)鍵字篩選日志文件
今天小編大家分享一篇python實(shí)現(xiàn)按關(guān)鍵字篩選日志文件方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12Python ckeditor富文本編輯器代碼實(shí)例解析
這篇文章主要介紹了Python ckeditor富文本編輯器代碼實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06Python實(shí)現(xiàn)基本Socket服務(wù)端與客戶端通信的完整代碼
這篇文章主要介紹了Python實(shí)現(xiàn)基本Socket服務(wù)端與客戶端通信,分步詳解與完整代碼都有,按需所求即可,對Python Socket服務(wù)端與客戶端通信相關(guān)知識感興趣的朋友一起看看吧2023-06-06