自定義模塊 和開源模塊的使用參考 http://www.cnblogs.com/wupeiqi/articles/4963027.html
1 1 >>> import time 2 2 >>> time.time() 3 3 1491064723.808669 4 4 >>> # time.time()返回當前時間的時間戳timestamp(定義爲從格林威治時間1970年01月01日00時00分00秒起至如今的總秒數)的方法,無參數 5 5 >>> time.asctime() 6 6 'Sun Apr 2 00:39:32 2017' 7 7 >>> # time.asctime()把struct_time對象格式轉換爲字符串格式爲'Sun Apr 2 00:39:32 2017' 8 8 >>> time.asctime(time.gmtime()) 9 9 'Sat Apr 1 16:41:41 2017' 10 10 >>> time.asctime(time.localtime()) 11 11 'Sun Apr 2 00:42:06 2017' 12 12 >>> time.ctime() 13 13 'Sun Apr 2 00:42:29 2017' 14 14 >>> # time.ctime()把時間戳轉換爲字符串格式'Sun Apr 2 00:42:29 2017',默認爲當前時間戳 15 15 >>> time.ctime(1491064723.808669) 16 16 'Sun Apr 2 00:38:43 2017' 17 17 >>> time.altzone # 返回與utc時間的時間差,以秒計算 18 18 -32400 19 19 >>> time.localtime() # 把時間戳轉換爲struct_time對象格式,默認返回當前時間戳 20 20 time.struct_time(tm_year=2017, tm_mon=4, tm_mday=2, tm_hour=0, tm_min=45, tm_sec=26, tm_wday=6, tm_yday=92, tm_isdst=0) 21 21 >>> time.localtime(1491064723.808669) 22 22 time.struct_time(tm_year=2017, tm_mon=4, tm_mday=2, tm_hour=0, tm_min=38, tm_sec=43, tm_wday=6, tm_yday=92, tm_isdst=0) 23 23 >>> 24 24 >>> time.gmtime() # 將utc時間戳轉換成struct_time對象格式,默認返回當前時間的 25 25 time.struct_time(tm_year=2017, tm_mon=4, tm_mday=1, tm_hour=16, tm_min=46, tm_sec=32, tm_wday=5, tm_yday=91, tm_isdst=0) 26 26 >>> time.gmtime(1491064723.808669) 27 27 time.struct_time(tm_year=2017, tm_mon=4, tm_mday=1, tm_hour=16, tm_min=38, tm_sec=43, tm_wday=5, tm_yday=91, tm_isdst=0) 28 28 >>> 29 29 >>> 30 30 >>> time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) # 將本地時間的struct_time格式轉成自定義字符串格式 2017-04-01 23:15:47 31 31 '2017-04-02 00:47:49' 32 32 >>> 33 33 >>> time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime()) # 將utc時間的struct_time格式轉成自定義字符串格式 2017-04-01 23:15:47 34 34 '2017-04-01 16:48:27' 35 35 >>> 36 36 >>> time.strptime('2017-04-02 00:47:49', '%Y-%m-%d %H:%M:%S') # 將 日期字符串 轉成 struct_time時間對象格式,注意轉換後的tm_isdst=-1()夏令時狀態 37 37 time.struct_time(tm_year=2017, tm_mon=4, tm_mday=2, tm_hour=0, tm_min=47, tm_sec=49, tm_wday=6, tm_yday=92, tm_isdst=-1) 38 38 >>> 39 39 >>> time.mktime(time.localtime()) 40 40 1491065416.0 41 41 >>> # 將struct_tiame時間對象轉成時間戳 結果返回1491061855.0 ,忽略小於秒的時間(忽略小數點後面) 42 42 >>> 43 43 >>> time.mktime(time.localtime(1491061855.0011407)) 44 44 1491061855.0 45 45 >>> # 結果返回1491061855.0 ,忽略小於秒的時間(忽略小數點後面) 46 46 >>> 47 47 >>> time.mktime(time.gmtime(1491061855.0011407)) 48 48 1491033055.0 49 49 >>> 50 50 >>> # 結果返回1491033055.0 ,忽略小於秒的時間(忽略小數點後面) 51 51 >>>
時間轉換關係圖html
格式字符及意義python
%a 星期的簡寫。如 星期三爲Web
%A 星期的全寫。如 星期三爲Wednesday
%b 月份的簡寫。如4月份爲Apr
%B月份的全寫。如4月份爲April
%c: 日期時間的字符串表示。(如: 04/07/10 10:43:39)
%d: 日在這個月中的天數(是這個月的第幾天)
%f: 微秒(範圍[0,999999])
%H: 小時(24小時制,[0, 23])
%I: 小時(12小時制,[0, 11])
%j: 日在年中的天數 [001,366](是當年的第幾天)
%m: 月份([01,12])
%M: 分鐘([00,59])
%p: AM或者PM
%S: 秒(範圍爲[00,61],爲何不是[00, 59],參考python手冊~_~)
%U: 周在當年的週數當年的第幾周),星期天做爲周的第一天
%w: 今天在這周的天數,範圍爲[0, 6],6表示星期天
%W: 周在當年的週數(是當年的第幾周),星期一做爲周的第一天
%x: 日期字符串(如:04/07/10)
%X: 時間字符串(如:10:43:39)
%y: 2個數字表示的年份
%Y: 4個數字表示的年份
%z: 與utc時間的間隔 (若是是本地時間,返回空字符串)
%Z: 時區名稱(若是是本地時間,返回空字符串)git
datetime模塊,方便時間計算正則表達式
1 >>> import datetime 2 >>> datetime.datetime.now() 3 datetime.datetime(2017, 4, 7, 16, 52, 3, 199458) 4 # 返回一組數據(年,月,日,小時,分鐘,秒,微秒) 5 6 >>> print(datetime.datetime.now()) 7 2017-04-07 16:52:55.000164 8 # 打印返回格式(固定) 9 10 >>> datetime.datetime.now()+datetime.timedelta(days=3) 11 datetime.datetime(2017, 4, 10, 16, 53, 51, 180847) 12 # 時間加(減),能夠是日,秒,微秒,毫秒,分,小時,周 13 #days=0, seconds=0, microseconds=0,milliseconds=0, minutes=0, hours=0, weeks=0 14 >>> print(datetime.datetime.now()+datetime.timedelta(weeks=1)) 15 2017-04-17 16:54:08.916243 16 17 >>> datetime.datetime.now().replace(minute=3,hour=2) 18 datetime.datetime(2017, 4, 7, 2, 3, 11, 163663) 19 # 時間替換 20 21 >>> datetime.datetime.now() 22 datetime.datetime(2017, 4, 7, 16, 58, 22, 195439) 23 24 >>> datetime.datetime.now().replace(day=1,month=1) 25 datetime.datetime(2017, 1, 1, 16, 59, 13, 210556) 26 >>> 27 # 直接替換相應位置數據
1 import random 2 >>> print(random.random()) 3 0.5364503211492734 4 >>> print(random.randint(1,10)) 5 3 6 >>> # 整數1-10(包括10),隨機取一個值 7 >>> 8 >>> 9 >>> 10 >>> print(random.randrange(1, 10)) 11 8 12 >>> # 整數1-10(不包括10),隨機取一個值
生成隨機驗證碼shell
1 import random 2 3 checkcode = '' 4 for i in range(6): 5 current = random.randrange(0, 6) 6 if current != i and current+1 != i: 7 temp = chr(random.randint(65, 90)) 8 # 65-90是A-Z 9 elif current+1 == i: 10 temp = chr(random.randint(97, 122)) 11 # 97-122是a-z 12 else: 13 temp = random.randint(0, 9) 14 checkcode += str(temp) 15 print(checkcode) 16 17 # 一共6位驗證碼, 18 # 第一位有1/6概率是數字,其它都是大寫字母 19 # 第二到第六位,都是有1/6概率是小寫字母,1/6概率是數字,其它都是大寫字母
提供對操做系統進行調用的接口安全
1 os.getcwd() 獲取當前工做目錄,即當前python腳本工做的目錄路徑 2 os.chdir("dirname") 改變當前腳本工做目錄;至關於shell下cd 3 os.curdir 返回當前目錄: ('.') 4 os.pardir 獲取當前目錄的父目錄字符串名:('..') 5 os.makedirs('dirname1/dirname2') 可生成多層遞歸目錄 6 os.removedirs('dirname1') 若目錄爲空,則刪除,並遞歸到上一級目錄,如若也爲空,則刪除,依此類推 7 os.mkdir('dirname') 生成單級目錄;至關於shell中mkdir dirname 8 os.rmdir('dirname') 刪除單級空目錄,若目錄不爲空則沒法刪除,報錯;至關於shell中rmdir dirname 9 os.listdir('dirname') 列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印 10 os.remove() 刪除一個文件 11 os.rename("oldname","newname") 重命名文件/目錄 12 os.stat('path/filename') 獲取文件/目錄信息 13 os.sep 輸出操做系統特定的路徑分隔符,win下爲"\\",Linux下爲"/" 14 os.linesep 輸出當前平臺使用的行終止符,win下爲"\t\n",Linux下爲"\n" 15 os.pathsep 輸出用於分割文件路徑的字符串 16 os.name 輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix' 17 os.system("bash command") 運行shell命令,直接顯示 18 os.environ 獲取系統環境變量 19 os.path.abspath(path) 返回path規範化的絕對路徑 20 os.path.split(path) 將path分割成目錄和文件名二元組返回 21 os.path.dirname(path) 返回path的目錄。其實就是os.path.split(path)的第一個元素 22 os.path.basename(path) 返回path最後的文件名。如何path以/或\結尾,那麼就會返回空值。即os.path.split(path)的第二個元素 23 os.path.exists(path) 若是path存在,返回True;若是path不存在,返回False 24 os.path.isabs(path) 若是path是絕對路徑,返回True 25 os.path.isfile(path) 若是path是一個存在的文件,返回True。不然返回False 26 os.path.isdir(path) 若是path是一個存在的目錄,則返回True。不然返回False 27 os.path.join(path1[, path2[, ...]]) 將多個路徑組合後返回,第一個絕對路徑以前的參數將被忽略 28 os.path.getatime(path) 返回path所指向的文件或者目錄的最後存取時間 29 os.path.getmtime(path) 返回path所指向的文件或者目錄的最後修改時間
更多os模塊猛擊這裏bash
用於提供對解釋器相關的操做網絡
1 sys.argv 命令行參數List,第一個元素是程序自己路徑 2 sys.exit(n) 退出程序,正常退出時exit(0) 3 sys.version 獲取Python解釋程序的版本信息 4 sys.maxint 最大的Int值 5 sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值 6 sys.platform 返回操做系統平臺名稱 7 sys.stdout.write('please:') 8 val = sys.stdin.readline()[:-1]
更多sys模塊猛擊這裏dom
高級的 文件、文件夾、壓縮包 處理模塊ide
shutil.copyfileobj(fsrc, fdst)
將文件內容拷貝到另外一個文件中,能夠部份內容,以下(注意須要打開文件):
1 import shutil 2 3 with open('testfile', 'r', encoding='utf-8') as f,\ 4 open('testfile1', 'w', encoding='utf-8') as f1: 5 shutil.copyfileobj(f, f1)
shutil.copyfile(src, dst)
僅拷貝文件
用法是shutil.copyfile(src_path, dst_path),以下:
import shutil shutil.copyfile(r'C:\Users\筆記.txt', r'C:\test1\筆記.txt')
shutil.copystat(src, dst)
僅拷貝狀態信息,包括:mode bits, atime, mtime, flags.用法格式同shutil.copyfile(src, dst)
shutil.copymode(src, dst)
僅拷貝權限。內容、組、用戶均不變,用法格式同shutil.copyfile(src, dst)
shutil.copy(src, dst)
拷貝文件和權限,用法個是同shutil.copyfile(src, dst)
shutil.copy2(src, dst)
拷貝文件和狀態信息,用法個是同shutil.copyfile(src, dst)
shutil.copytree(src, dst, symlinks=False, ignore=None)
拷貝一個目錄,src是原目錄路徑,dst是新目錄路徑
shutil.rmtree(path)
刪除一個目錄,path爲目錄路徑
shutil.move(src, dst)
移動文件或目錄,src是原文件或目錄的路徑,dst是新目錄路徑!使用的copy2函數拷貝文件和狀態信息
1 import shutil 2 3 shutil.move(r'C:\Users\筆記.txt', r'C:\test1')
shutil.make_archive(base_name, format,...)
建立壓縮包並返回文件路徑,例如:zip、tar
1 #將 /Users/wupeiqi/Downloads/test 下的文件打包放置當前程序目錄 2 3 import shutil 4 ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test') 5 6 7 #將 /Users/wupeiqi/Downloads/test 下的文件打包放置 /Users/wupeiqi/目錄 8 import shutil 9 ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
shutil 對壓縮包的處理是調用 ZipFile 和 TarFile 兩個模塊來進行的,詳細:
import zipfile # 壓縮 z = zipfile.ZipFile('laxi.zip', 'w') z.write('a.log') z.write('data.data') z.close() # 解壓 z = zipfile.ZipFile('laxi.zip', 'r') z.extractall() z.close() zipfile 壓縮解壓
import tarfile # 壓縮 tar = tarfile.open('your.tar','w') tar.add('/Users/wupeiqi/PycharmProjects/bbs2.zip', arcname='bbs2.zip') # arcname指定壓縮目錄,不指定就默認文件絕對目錄 tar.add('/Users/wupeiqi/PycharmProjects/cmdb.zip', arcname='cmdb.zip') tar.close() # 解壓 tar = tarfile.open('your.tar','r') tar.extractall() # 可設置解壓地址 tar.close() tarfile 壓縮解壓
tarfile只打包不壓縮,zip會壓縮
logging 模塊
用於便捷記錄日誌且線程安全的模塊
1 import logging 2 3 4 logging.basicConfig(filename='log.log', 5 format='%(asctime)s %(filename)s : %(lineno)s -%(levelname)s : %(message)s', 6 datefmt='%m-%d-%Y %I:%M:%S %p', 7 level=10) 8 9 logging.debug('debug') 10 logging.info('info') 11 logging.warning('warning') 12 logging.error('error') 13 logging.critical('critical') 14 logging.log(10,'log')
對於等級level
CRITICAL level
=
50
FATAL
level
=
50
ERROR level
=
40
WARNING level
=
30
WARN
level
=
30
INFO level
=
20
DEBUG level
=
10
NOTSET level
=
0
日誌格式
%(name)s |
Logger的名字 |
%(levelno)s |
數字形式的日誌級別 |
%(levelname)s |
文本形式的日誌級別 |
%(pathname)s |
調用日誌輸出函數的模塊的完整路徑名,可能沒有 |
%(filename)s |
調用日誌輸出函數的模塊的文件名 |
%(module)s |
調用日誌輸出函數的模塊名 |
%(funcName)s |
調用日誌輸出函數的函數名 |
%(lineno)d |
調用日誌輸出函數的語句所在的代碼行 |
%(created)f |
當前時間,用UNIX標準的表示時間的浮 點數表示 |
%(relativeCreated)d |
輸出日誌信息時的,自Logger建立以 來的毫秒數 |
%(asctime)s |
字符串形式的當前時間。默認格式是 「2003-07-08 16:49:45,896」。逗號後面的是毫秒 |
%(thread)d |
線程ID。可能沒有 |
%(threadName)s |
線程名。可能沒有 |
%(process)d |
進程ID。可能沒有 |
%(message)s |
用戶輸出的消息 |
若是想同時把log打印在屏幕和文件日誌裏,就須要瞭解一點複雜的知識 了
Python 使用logging模塊記錄日誌涉及四個主要類,使用官方文檔中的歸納最爲合適:
logger提供了應用程序能夠直接使用的接口;
handler將(logger建立的)日誌記錄發送到合適的目的輸出;
filter提供了細度設備來決定輸出哪條日誌記錄;
formatter決定日誌記錄的最終輸出格式。
logger
每一個程序在輸出信息以前都要得到一個Logger。Logger一般對應了程序的模塊名,好比聊天工具的圖形界面模塊能夠這樣得到它的Logger:
LOG=logging.getLogger(」chat.gui」)
而核心模塊能夠這樣:
LOG=logging.getLogger(」chat.kernel」)
Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,critical爲最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增長或刪除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():能夠設置的日誌級別
handler
handler對象負責發送相關的信息到指定目的地。Python的日誌系統有多種Handler可使用。有些Handler能夠把信息輸出到控制檯,有些Logger能夠把信息輸出到文件,還有些 Handler能夠把信息發送到網絡上。若是以爲不夠用,還能夠編寫本身的Handler。能夠經過addHandler()方法添加多個多handler
Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
每一個Logger能夠附加多個Handler。接下來咱們就來介紹一些經常使用的Handler:
1) logging.StreamHandler
使用這個Handler能夠向相似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。它的構造函數是:
StreamHandler([strm])
其中strm參數是一個文件對象。默認是sys.stderr
2) logging.FileHandler
和StreamHandler相似,用於向一個文件輸出日誌信息。不過FileHandler會幫你打開這個文件。它的構造函數是:
FileHandler(filename[,mode])
filename是文件名,必須指定一個文件名。
mode是文件的打開方式。參見Python內置函數open()的用法。默認是’a',即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
這個Handler相似於上面的FileHandler,可是它能夠管理文件大小。當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立 一個新的同名日誌文件繼續輸出。好比日誌文件是chat.log。當chat.log達到指定的大小以後,RotatingFileHandler自動把 文件更名爲chat.log.1。不過,若是chat.log.1已經存在,會先把chat.log.1重命名爲chat.log.2。。。最後從新建立 chat.log,繼續輸出日誌信息。它的構造函數是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個參數和FileHandler同樣。
maxBytes用於指定日誌文件的最大文件大小。若是maxBytes爲0,意味着日誌文件能夠無限大,這時上面描述的重命名過程就不會發生。
backupCount用於指定保留的備份文件的個數。好比,若是指定爲2,當上面描述的重命名過程發生時,原有的chat.log.2並不會被改名,而是被刪除。
4) logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,而是間隔必定時間就 自動建立新的日誌文件。重命名的過程與RotatingFileHandler相似,不過新的文件不是附加數字,而是當前時間。它的構造函數是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數和backupCount參數和RotatingFileHandler具備相同的意義。
interval是時間間隔。
when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有如下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時表明星期一)
midnight 天天凌晨
正則表達式使用反斜杆(\)來轉義特殊字符,使其能夠匹配字符自己,而不是指定其餘特殊的含義。這可能會和python字面意義上的字符串轉義相沖突,這也許有些使人費解。好比,要匹配一個反斜杆自己,你也許要用'\\\\'來作爲正則表達式的字符串,由於正則表達式要是\\,而字符串裏,每一個反斜杆都要寫成\\。
你也能夠在字符串前加上 r 這個前綴來避免部分疑惑,由於 r 開頭的python字符串是 raw 字符串,因此裏面的全部字符都不會被轉義,好比r'\n'這個字符串就是一個反斜杆加上一字母n,而'\n'咱們知道這是個換行符。所以,上面的'\\\\'你也能夠寫成r'\\',這樣,應該就好理解不少了。能夠看下面這段
1 >>> import re 2 >>> s = '\x5c' 3 >>> print(s) 4 \ 5 >>> re.match('\\\\', s) #這樣能夠匹配 6 <_sre.SRE_Match object; span=(0, 1), match='\\'> 7 >>> re.match(r'\\', s) #這樣也能夠 8 <_sre.SRE_Match object; span=(0, 1), match='\\'> 9 >>> re.match('\\', s) #可是這樣不行 10 Traceback (most recent call last): 11 File "<pyshell#5>", line 1, in <module> 12 re.match('\\', s) #可是這樣不行 13 File "C:\Python36\lib\re.py", line 172, in match 14 return _compile(pattern, flags).match(string) 15 File "C:\Python36\lib\re.py", line 301, in _compile 16 p = sre_compile.compile(pattern, flags) 17 File "C:\Python36\lib\sre_compile.py", line 562, in compile 18 p = sre_parse.parse(p, flags) 19 File "C:\Python36\lib\sre_parse.py", line 848, in parse 20 source = Tokenizer(str) 21 File "C:\Python36\lib\sre_parse.py", line 231, in __init__ 22 self.__next() 23 File "C:\Python36\lib\sre_parse.py", line 245, in __next 24 self.string, len(self.string) - 1) from None 25 sre_constants.error: bad escape (end of pattern) at position 0 26 >>>
正則表達式語法
正則表達式(RE)指定一個與之匹配的字符集合;本模塊所提供的函數,將能夠用來檢查所給的字符串是否與指定的正則表達式匹配。
正則表達式能夠被鏈接,從而造成新的正則表達式;例如A和B都是正則表達式,那麼AB也是正則表達式。通常地,若是字符串p與A匹配,q與B匹配的話,那麼字符串pq也會與AB匹配,但A或者B裏含有邊界限定條件或者命名組操做的狀況除外。也就是說,複雜的正則表達式能夠用簡單的鏈接而成。
正則表達式能夠包含特殊字符和普通字符,大部分字符好比'A','a'和'0'都是普通字符,若是作爲正則表達式,它們將匹配它們自己。因爲正則表達式能夠鏈接,因此鏈接多個普通字符而成的正則表達式last也將匹配'last'。(後面將用不帶引號的表示正則表達式,帶引號的表示字符串)
下面就來介紹正則表達式的特殊字符:
'.'
點號,在普通模式,它匹配除換行符外的任意一個字符;若是指定了 DOTALL 標記,匹配包括換行符之內的任意一個字符。
'^'
尖尖號,匹配一個字符串的開始,在 MULTILINE 模式下,也將匹配任意一個新行的開始。
'$'
美圓符號,匹配一個字符串的結尾或者字符串最後面的換行符,在 MULTILINE 模式下,也匹配任意一行的行尾。也就是說,普通模式下,foo.$去搜索'foo1\nfoo2\n'只會找到'foo2′,可是在 MULTILINE 模式,還能找到 ‘foo1′,並且就用一個 $ 去搜索'foo\n'的話,會找到兩個空的匹配:一個是最後的換行符,一個是字符串的結尾,演示:
1 >>> re.findall('(foo.$)', 'foo1\nfoo2\n') 2 ['foo2'] 3 >>> re.findall('(foo.$)', 'foo1\nfoo2\n', re.MULTILINE) 4 ['foo1', 'foo2'] 5 >>> re.findall('($)', 'foo\n') 6 ['', ''] 7 >>>
'*'
星號,指定將前面的RE重複0次或者任意屢次,並且老是試圖儘可能屢次地匹配。
'+'
加號,指定將前面的RE重複1次或者任意屢次,並且老是試圖儘可能屢次地匹配。
'?'
問號,指定將前面的RE重複0次或者1次,若是有的話,也儘可能匹配1次。
*?, +?, ??
從前面的描述能夠看到'*','+'和'?'都是貪婪的,但這也許並非咱們說要的,因此,能夠在後面加個問號,將策略改成非貪婪,只匹配儘可能少的RE。示例,體會二者的區別:
1 >>> re.findall('<(.*)>', '<H1>title</H1>') 2 ['H1>title</H1'] 3 >>> re.findall('<(.*?)>', '<H1>title</H1>') 4 ['H1', '/H1']
{m,n}
m和n都是數字,指定將前面的RE重複m到n次,例如a{3,5}匹配3到5個連續的a。注意,若是省略m,將匹配0到n個前面的RE;若是省略n,將匹配n到無窮多個前面的RE;固然中間的逗號是不能省略的,否則就變成前面那種形式了。
{m,n}?
前面說的{m,n},也是貪婪的,a{3,5}若是有5個以上連續a的話,會匹配5個,這個也能夠經過加問號改變。a{3,5}?若是可能的話,將只匹配3個a。
'\'
反斜杆,轉義'*','?'等特殊字符,或者指定一個特殊序列(下面會詳述)
因爲以前所述的緣由,強烈建議用raw字符串來表述正則。
[]
方括號,用於指定一個字符的集合。能夠單獨列出字符,也能夠用'-'鏈接起止字符以表示一個範圍。特殊字符在中括號裏將失效,好比[akm$]就表示字符'a','k','m',或'$',在這裏$也變身爲普通字符了。[a-z]匹配任意一個小寫字母,[a-zA-Z0-9]匹配任意一個字母或數字。若是你要匹配']'或'-'自己,你須要加反斜杆轉義,或者是將其置於中括號的最前面,好比[]]能夠匹配']'
你還能夠對一個字符集合取反,以匹配任意不在這個字符集合裏的字符,取反操做用一個'^'放在集合的最前面表示,放在其餘地方的'^'將不會起特殊做用。例如[^5]將匹配任意不是'5'的字符;[^^]將匹配任意不是'^'的字符。
注意:在中括號裏,+、*、(、)這類字符將會失去特殊含義,僅做爲普通字符。反向引用也不能在中括號內使用。
'|'
管道符號,A和B是任意的RE,那麼A|B就是匹配A或者B的一個新的RE。任意個數的RE均可以像這樣用管道符號間隔鏈接起來。這種形式能夠被用於組中(後面將詳述)。對於目標字符串,被'|'分割的RE將自左至右一一被測試,一旦有一個測試成功,後面的將再也不被測試,即便後面的RE可能能夠匹配更長的串,換句話說,'|'操做符是非貪婪的。要匹配字面意義上的'|',能夠用反斜杆轉義:\|,或是包含在反括號內:[|]。
(...)
匹配圓括號裏的RE匹配的內容,並指定組的開始和結束位置。組裏面的內容能夠被提取,也能夠採用\number這樣的特殊序列,被用於後續的匹配。要匹配字面意義上的'('和')',能夠用反斜杆轉義:\(、\),或是包含在反括號內:[(]、[)]。
(?...)
這是一個表達式的擴展符號。'?'後的第一個字母決定了整個表達式的語法和含義,除了(?P...)之外,表達式不會產生一個新的組。下面介紹幾個目前已被支持的擴展:
(?iLmsux)
'i'、'L'、'm'、's'、'u'、'x'裏的一個或多個字母。表達式不匹配任何字符,可是指定相應的標誌:re.I(忽略大小寫)、re.L(依賴locale)、re.M(多行模式)、re.S(.匹配全部字符)、re.U(依賴Unicode)、re.X(詳細模式)。關於各個模式的區別,下面會有專門的一節來介紹的。使用這個語法能夠代替在re.compile()的時候或者調用的時候指定flag參數。
例如,上面舉過的例子,能夠改寫成這樣(和指定了re.MULTILINE是同樣的效果):
1 >>> re.findall('(?m)(foo.$)', 'foo1\nfoo2\n') 2 ['foo1', 'foo2'] 3 >>> re.findall('(foo.$)', 'foo1\nfoo2\n', re.MULTILINE) 4 ['foo1', 'foo2'] 5 >>>
另外,還要注意(?x)標誌若是有的話,要放在最前面。
(?:...)
匹配內部的RE所匹配的內容,可是不創建組。
(?P<name>...)
和普通的圓括號相似,可是子串匹配到的內容將能夠用命名的name參數來提取。組的name必須是有效的python標識符,並且在本表達式內不重名。命名了的組和普通組同樣,也用數字來提取,也就是說名字只是個額外的屬性。
演示一下:
1 >>> m=re.match('(?P<var>[a-zA-Z_]\w*)', 'abc=123') 2 >>> m.group('var') 3 'abc' 4 >>> m.group(1) 5 'abc' 6 >>>
匹配以前以name命名的組裏的內容。
演示一下:
1 >>> re.match('<(?P<tagname>\w*)>.*</(?P=tagname)>', '<h1>xxx</h2>') #這個不匹配 2 >>> re.match('<(?P<tagname>\w*)>.*</(?P=tagname)>', '<h1>xxx</h1>') #這個匹配 3 <_sre.SRE_Match object; span=(0, 12), match='<h1>xxx</h1>'> 4 >>>
(?#...)
註釋,圓括號裏的內容會被忽略。
(?=...)
若是 ... 匹配接下來的字符,纔算匹配,可是並不會消耗任何被匹配的字符。例如 Isaac (?=Asimov) 只會匹配後面跟着 'Asimov' 的 'Isaac ',這個叫作「前瞻斷言」。
(?!...)
和上面的相反,只匹配接下來的字符串不匹配 ... 的串,這叫作「反前瞻斷言」。
(?<=...)
只有噹噹前位置以前的字符串匹配 ... ,整個匹配纔有效,這叫「後顧斷言」。字符串'abcdef'能夠匹配正則(?<=abc)def,由於會後向查找3個字符,看是否爲abc。因此內置的子RE,須要是固定長度的,好比能夠是abc、a|b,但不能是a*、a{3,4}。注意這種RE永遠不會匹配到字符串的開頭。舉個例子,找到連字符('-')後的單詞:
1 >>> m = re.search('(?<=-)\w+', 'spam-egg') 2 >>> m.group(0) 3 'egg'
(?<!...)
同理,這個叫作「反後顧斷言」,子RE須要固定長度的,含義是前面的字符串不匹配 ... 整個纔算匹配。
(?(id/name)yes-pattern|no-pattern)
若有由id或者name指定的組存在的話,將會匹配yes-pattern,不然將會匹配no-pattern,一般狀況下no-pattern也能夠省略。例如:(<)?(\w+@\w+(?:\.\w+)+)(?(1)>)能夠匹配 '<user@host.com>' 和 'user@host.com',可是不會匹配 '<user@host.com'。
下面列出以'\'開頭的特殊序列。若是某個字符沒有在下面列出,那麼RE的結果會只匹配那個字母自己,好比,\$只匹配字面意義上的'$'。
字符:
. 匹配除換行符之外的任意字符
\w 匹配字母或數字或下劃線或漢字
\s 匹配任意的空白符
\d 匹配數字
\b 匹配單詞的開始或結束
^ 匹配字符串的開始
$ 匹配字符串的結束
次數:
* 重複零次或更屢次
+ 重複一次或更屢次
? 重複零次或一次
{n} 重複n次
{n,} 重複n次或更屢次
{n,m} 重複n到m次
匹配之搜索
python提供了兩種基於正則表達式的操做:匹配(match)從字符串的開始檢查字符串是否個正則匹配。而搜索(search)檢查字符串任意位置是否有匹配的子串(perl默認就是如此)。
注意,即便search的正則以'^'開頭,match和search也仍是有許多不一樣的。
1 >>> re.match("c", "abcdef") # 不匹配 2 >>> re.search("c", "abcdef") # 匹配 3 <_sre.SRE_Match object at ...>
模塊的屬性和方法
re.compile(pattern[, flags])
把一個正則表達式pattern編譯成正則對象,以即可以用正則對象的match和search方法。
獲得的正則對象的行爲(也就是模式)能夠用flags來指定,值能夠由幾個下面的值OR獲得。
如下兩段內容在語法上是等效的:
prog = re.compile(pattern) result = prog.match(string)
result = re.match(pattern, string)
區別是,用了re.compile之後,正則對象會獲得保留,這樣在須要屢次運用這個正則對象的時候,效率會有較大的提高。再用上面用過的例子來演示一下,用相同的正則匹配相同的字符串,執行100萬次,就體現出compile的效率了(數據來自個人臺式電腦英特爾 Core i5-6500 @ 3.20GHz 四核):
>>> import timeit >>> timeit.timeit( setup="import re; reg = re.compile('<(?P<tagname>\w*)>.*</(?P=tagname)>')", stmt="reg.match('<h1>xxx</h1>')", number=1000000) 0.3993007156773078 >>> timeit.timeit( setup='import re', stmt="re.match('<(?P<tagname>\w*)>.*</(?P=tagname)>', '<h1>xxx</h1>')", number=1000000) 0.8457147421697897 >>>
re.I
re.IGNORECASE
讓正則表達式忽略大小寫,這樣一來,[A-Z]也能夠匹配小寫字母了。此特性和locale無關。
re.L
re.LOCALE
讓\w、\W、\b、\B、\s和\S依賴當前的locale。
re.M
re.MULTILINE
影響'^'和'$'的行爲,指定了之後,'^'會增長匹配每行的開始(也就是換行符後的位置);'$'會增長匹配每行的結束(也就是換行符前的位置)。
re.S
re.DOTALL
影響'.'的行爲,平時'.'匹配除換行符之外的全部字符,指定了本標誌之後,也能夠匹配換行符。
re.U
re.UNICODE
讓\w、\W、\b、\B、\d、\D、\s和\S依賴Unicode庫。
re.X
re.VERBOSE
運用這個標誌,你能夠寫出可讀性更好的正則表達式:除了在方括號內的和被反斜槓轉義的之外的全部空白字符,都將被忽略,並且每行中,一個正常的井號後的全部字符也被忽略,這樣就能夠方便地在正則表達式內部寫註釋了。也就是說,下面兩個正則表達式是等效的:
a = re.compile(r"""\d + # the integral part
\. # the decimal point \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*") re.search(pattern, string[, flags])
掃描string,看是否有個位置能夠匹配正則表達式pattern。若是找到了,就返回一個MatchObject的實例,不然返回None,注意這和找到長度爲0的子串含義是不同的。搜索過程受flags的影響。
re.match(pattern, string[, flags])
若是字符串string的開頭和正則表達式pattern匹配的話,返回一個相應的MatchObject的實例,不然返回None
注意:要在字符串的任意位置搜索的話,須要使用上面的search()。
re.split(pattern, string[, maxsplit=0])
用匹配pattern的子串來分割string,若是pattern裏使用了圓括號,那麼被pattern匹配到的串也將做爲返回值列表的一部分。若是maxsplit不爲0,則最多被分割爲maxsplit個子串,剩餘部分將整個地被返回。
>>> re.split('\W+', 'Words, words, words.') ['Words', 'words', 'words', ''] >>> re.split('(\W+)', 'Words, words, words.') ['Words', ', ', 'words', ', ', 'words', '.', ''] >>> re.split('\W+', 'Words, words, words.', 1) ['Words', 'words, words.']
若是正則有圓括號,而且能夠匹配到字符串的開始位置的時候,返回值的第一項,會多出一個空字符串。匹配到字符結尾也是一樣的道理:
>>> re.split('(\W+)', '...words, words...') ['', '...', 'words', ', ', 'words', '...', '']
注意,split不會被零長度的正則所分割,例如:
>>> re.split('x*', 'foo') ['foo'] >>> re.split("(?m)^$", "foo\n\nbar\n") ['foo\n\nbar\n']
re.findall(pattern, string[, flags])
以列表的形式返回string裏匹配pattern的不重疊的子串。string會被從左到右依次掃描,返回的列表也是從左到右一次匹配到的。若是pattern裏含有組的話,那麼會返回匹配到的組的列表;若是pattern裏有多個組,那麼各組會先組成一個元組,而後返回值將是一個元組的列表。
因爲這個函數不會涉及到MatchObject之類的概念,因此,對新手來講,應該是最好理解也最容易使用的一個函數了。下面就此來舉幾個簡單的例子:
#簡單的findall >>> re.findall('\w+', 'hello, world!') ['hello', 'world'] #這個返回的就是元組的列表 >>> re.findall('(\d+)\.(\d+)\.(\d+)\.(\d+)', 'My IP is 192.168.0.2, and your is 192.168.0.3.') [('192', '168', '0', '2'), ('192', '168', '0', '3')] re. finditer(pattern, string[, flags])
和上面的findall()相似,但返回的是MatchObject的實例的迭代器。
仍是例子說明問題:
>>> for m in re.finditer('\w+', 'hello, world!'): print(m.group()) hello world >>>
re.sub(pattern, repl, string[, count])
替換,將string裏,匹配pattern的部分,用repl替換掉,最多替換count次(剩餘的匹配將不作處理),而後返回替換後的字符串。若是string裏沒有能夠匹配pattern的串,將被原封不動地返回。repl能夠是一個字符串,也能夠是一個函數(也能夠參考我之前的例子)。若是repl是個字符串,則其中的反斜杆會被處理過,好比 \n 會被轉成換行符,反斜杆加數字會被替換成相應的組,好比 \6 表示pattern匹配到的第6個組的內容。
例子:
>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', r'static PyObject*\npy_\1(void)\n{', 'def myfunc():') 'static PyObject*\npy_myfunc(void)\n{'
若是repl是個函數,每次pattern被匹配到的時候,都會被調用一次,傳入一個匹配到的MatchObject對象,須要返回一個字符串,在匹配到的位置,就填入返回的字符串。
例子:
>>> def dashrepl(matchobj): if matchobj.group(0) == '-': return ' ' else:
return '-' >>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 'pro--gram files' >>>
零長度的匹配也會被替換,好比:
>>> re.sub('x*', '-', 'abcxxd') '-a-b-c-d-' >>>
特殊地,在替換字符串裏,若是有\g這樣的寫法,將匹配正則的命名組(前面介紹過的,(?P...)這樣定義出來的東西)。\g這樣的寫法,也是數字的組,也就是說,\g<2>通常和\2是等效的,可是萬一你要在\2後面緊接着寫上字面意義的0,你就不能寫成\20了(由於這表明第20個組),這時候必須寫成\g<2>0,另外,\g<0>表明匹配到的整個子串。
例子:
>>> re.sub('-(\d+)-', '-\g<1>0\g<0>', 'a-11-b-22-c') 'a-110-11-b-220-22-c' >>>
更多正則表達式請看http://www.jb51.net/article/50511.htm