第一章:正則表達式

目錄css

  一. 正則表達式html

  二. 特殊的元字符前端

  三. python3的re模塊方法html5

  四. python3的re模塊練習python

  五. 第一章課後練習題正則表達式

  六. re模塊綜合應用之計算器算法

一. 正則表達式數據庫

  正則表達式是由一堆字符和特殊符號組成的字符串。它能夠爲咱們提供高級的文本搜索,匹配,替換功能。固然,正則表達式也不是python獨有的一種模式,而是凌駕於語言之上的一種跨平臺的通用標準。當咱們學會了正則表達式以後,將會可以更加容易的處理咱們的文本和數據。讓咱們開始正則之旅吧。express

二. 特殊的元字符編程

  正則表達式本質上就是一堆字符串,只不過構成這個字符串的每個字符都是有特別意義的,咱們想要去真正的去了解正則表達式,就必需要清楚的記得特殊字符的含義。下圖是python核心編程中關於元字符的描述。雖然有不少,可是你必定要背會(固然在學的過程當中你會發現其實也沒有那麼難背,用着用着就記住了,可是仍是提醒,無論是什麼方法,必定要記住)。

  

  

   在咱們真正開始正則表達式以前,咱們首先要了解一個工具,那就是python的re模塊,快速的瞭解,只須要知道經過這個模塊咱們能夠查看寫出來的正則表達式是否準確就能夠了。以後咱們會再去詳細的查看,使用方法以下:

>>> re.search('^s.*$', 'sllsljegleg')# 第一個參數:就是咱們寫出來的正則表達式(從表面上看就是字符串)第二個參數:就是咱們匹配的字符串,若是匹配到了就返回值
<_sre.SRE_Match object; span=(0, 11), match='sllsljegleg'> # 最後match後面的就是咱們匹配到的字符串
>>> re.search('^s.*$', 'llsljegleg') # 若是沒有匹配到就沒有顯示
>>>

第一類: 位置匹配

  位置匹配就是專門用來描述位置的元字符,有四個: 【^,$, \A,\Z】(注意是有大小寫之分的),^ 和\A都表示字符串的開頭,$ 和\Z都表示字符串的結尾,爲何會有兩個元字符去表示同一個事物呢?這是由於在一些國際鍵盤上是沒有脫字符的,因此設計的時候又設計了\A和\Z來表示。

>>> re.search('^From','From to China')  # 以From開頭的字符串
<_sre.SRE_Match object; span=(0, 4), match='From'>


>>> re.search('/bin/tcsh$', 'python /bin/tcsh') # 以/bin/tcsh結尾的字符串  
<_sre.SRE_Match object; span=(7, 16), match='/bin/tcsh'>

>>> re.search('^Subject:hi$', 'Subject:hi')  # 若是前面有脫字符,後面美圓符,就表明只匹配裏面的值,此例中就是隻匹配Subject:hi
<_sre.SRE_Match object; span=(0, 10), match='Subject:hi'>
>>>

  須要匹配【$】和脫字符【^】的時候怎麼作呢,經過【\】斜槓進行轉義

>>> re.search('\$', '$') 經過\轉義就能夠匹配到$ 符了 <_sre.SRE_Match object; span=(0, 1), match='$'>
>>> re.search('\^\$', 'hello ^$') <_sre.SRE_Match object; span=(6, 8), match='^$'>
>>>

  【\A, \Z】的用法和^$的用法是同樣的

>>> re.search('\AFrom','From to China') # 以From開頭的字符串 <_sre.SRE_Match object; span=(0, 4), match='From'>


>>> re.search('/bin/tcsh\Z', 'python /bin/tcsh') # 以/bin/tcsh結尾的字符串 <_sre.SRE_Match object; span=(7, 16), match='/bin/tcsh'>

>>> re.search('\ASubject:hi\Z', 'Subject:hi') # 若是前面有脫字符,後面美圓符,就表明只匹配裏面的值,此例中就是隻匹配Subject:hi <_sre.SRE_Match object; span=(0, 10), match='Subject:hi'>
>>>
\A和\Z的使用方法

  【\b】匹配任何單詞邊界

>>> s = 'this island is beautiful'
>>> import re >>> re.search(r'\bis', s) # 此時咱們會發現匹配到了索引爲5,7的字符,也就是說island這個前面的is匹配到了 <_sre.SRE_Match object; span=(5, 7), match='is'>
>>> re.search(r'\bis\b', s) # 若是加上\b界定上單詞邊界以後就會之匹匹厄後面的is了,由於前面的is並非一個單詞 <_sre.SRE_Match object; span=(12, 14), match='is'>
>>>

第二類: 重複匹配

  重複匹配就是將以前匹配的正則表達式從新匹配多少次。重複匹配是正則表達式中基本上最經常使用的模式。

  【*】匹配前面正則表達式0次或者屢次

>>> re.search('\d\d*', '1') # 第一個\d匹配一個數字,第二個\d原本也是匹配一個數字,可是後面加上了一個*,表明前面能夠不匹配,也能夠匹配一次或者屢次 <_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search('\d\d*', '12') # 這個就是第二個\d匹配了1次 <_sre.SRE_Match object; span=(0, 2), match='12'>
>>> re.search('\d\d*', '123') # 這個就是第二個\d匹配了2次 <_sre.SRE_Match object; span=(0, 3), match='123'>
>>>

  【+】匹配前面正則表達式1次或者屢次

>>> re.search('\d\d+', '1') # 第一個\d匹配到了1,可是第二個\d後面有+表明最少匹配一次,可是字符串沒有數字了,因此就沒有匹配到值 >>> re.search('\d\d+', '12') # 這個表明第二個\d匹配了一次 <_sre.SRE_Match object; span=(0, 2), match='12'>
>>> re.search('\d\d+', '123')  # 這個表明第二個\d匹配了兩次 <_sre.SRE_Match object; span=(0, 3), match='123'>
>>>

  【?】匹配前面正則表達式0次或者1次

>>> re.search('\d\d?', '1') # 第一個\d匹配到了1,可是第二個\d後面有?說明能夠匹配0次,也就是不匹配 <_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search('\d\d?', '12') # 第二個\d匹配了1次 <_sre.SRE_Match object; span=(0, 2), match='12'>
>>> re.search('\d\d?', '123') # 雖然匹配到了,可是發現匹配到的值仍是12,最多隻能匹配一次 <_sre.SRE_Match object; span=(0, 2), match='12'>
>>>

  【{n}】匹配前面正則表達式n次

>>> re.search('\d\d{2}', '12') >>> re.search('\d\d{2}', '1') >>> re.search('\d\d{2}', '123') # {2}表明前面的\d必需要匹配兩次,因此只能匹配到123 <_sre.SRE_Match object; span=(0, 3), match='123'>
>>> re.search('\d\d{2}', '1234') <_sre.SRE_Match object; span=(0, 3), match='123'>
>>>

  【{n, m}】匹配前面正則表達式n到m次

>>> re.search('\d\d{2,4}', '12') >>> re.search('\d\d{2,4}', '123') # {2,4}表明匹配前面\d2次到4次,所以咱們能夠發現最少要匹配兩次,最多要匹配4次 <_sre.SRE_Match object; span=(0, 3), match='123'>
>>> re.search('\d\d{2,4}', '1234') <_sre.SRE_Match object; span=(0, 4), match='1234'>
>>> re.search('\d\d{2,4}', '12345') <_sre.SRE_Match object; span=(0, 5), match='12345'>
>>> re.search('\d\d{2,4}', '123456') <_sre.SRE_Match object; span=(0, 5), match='12345'>
>>>

  重複匹配的例子

# 1. 匹配字符d或b以後跟着一個o最後能夠跟着一個t也能夠不跟着一個t的例子
>>> re.search('[db]ot?', 'do') <_sre.SRE_Match object; span=(0, 2), match='do'>
>>> re.search('[db]ot?', 'dot') <_sre.SRE_Match object; span=(0, 3), match='dot'>
>>> re.search('[db]ot?', 'bo') <_sre.SRE_Match object; span=(0, 2), match='bo'>
>>> re.search('[db]ot?', 'bot') <_sre.SRE_Match object; span=(0, 3), match='bot'>
>>>

# 2. 匹配9-16位的信用卡號
>>> re.search('[0-9]{9, 16}', '1234567890')  # 注意不能加空格
>>> re.search('[0-9]{9,16}', '1234567890') <_sre.SRE_Match object; span=(0, 10), match='1234567890'>
>>>

# 3. 匹配所有有效的html標籤
>>> re.search('</?[^>]+>', '</>') #/?表明/能夠不出現,表明的是開頭的標籤,也能夠出現1次,表明的是結尾的標籤,[^>]表明的是除了>的任何字符,後面跟上+,也就是說除了>的任何字符出現一次或者屢次 <_sre.SRE_Match object; span=(0, 3), match='</>'>
>>> re.search('</?[^>]+>', '<hello>') <_sre.SRE_Match object; span=(0, 7), match='<hello>'>
>>>

第三類: 範圍匹配

  範圍匹配是經過一個或者一組特殊的字符表明一個範圍的數據。例如:【\d】表明的是0-9的數字數字。【大寫字母的都是與之相反的】

     【.】點表明的是除了換行符以外的任意的字符的匹配

>>> re.search('f.o', 'fao') # 匹配字母f和o之間的任何一個字符 <_sre.SRE_Match object; span=(0, 3), match='fao'>
>>> re.search('f.o', 'f#o') <_sre.SRE_Match object; span=(0, 3), match='f#o'>
>>> re.search('f.o', 'f9o') <_sre.SRE_Match object; span=(0, 3), match='f9o'>
>>> re.search('..', 'js') # 匹配任意的兩個字符 <_sre.SRE_Match object; span=(0, 2), match='js'>  
>>> re.search('..', 'ss') <_sre.SRE_Match object; span=(0, 2), match='ss'>
>>>

  【\d】表示0-9的任何十進制數字

>>> re.search('\d', '1') # 匹配0-9的任何一個字符 <_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search('\d', '2') <_sre.SRE_Match object; span=(0, 1), match='2'>
>>> re.search('\d', 'z') # z不是0-9因此匹配不到 >>>

  【\w】字母數字下劃線 至關於[a-zA-0-9_]的縮寫

>>> re.search('\w', '1') # 字母數字下滑先均可以匹配到,並且也只是匹配一個字符 <_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search('\w', 'a') <_sre.SRE_Match object; span=(0, 1), match='a'>
>>> re.search('\w', '_') <_sre.SRE_Match object; span=(0, 1), match='_'>
>>> re.search('\w', '#') # 由於#不在範圍以內,因此沒有匹配到 >>>

  \d和\w的一些例子

#1. 一個數字字母組成的字符串和一串由數字組成的字符串
>>> re.search('\w+-\d+', 'ab123sejg-123456') # \w表明數字字母,+表明前面的數字字母能夠出現一次或者屢次,也就是把字母數字組成的字符串表示好了,\d+也是同樣的效果,表明的是一串由數字組成的字符串 <_sre.SRE_Match object; span=(0, 16), match='ab123sejg-123456'>
>>>

#2. 以字母開頭,其他字符是字母或者數字
 >>> re.search('^[A-Za-z]\w*', 'a123lsege') <_sre.SRE_Match object; span=(0, 9), match='a123lsege'>
>>>

#3. 美國電話號碼的格式 800-555-1212
>>>
>>> re.search('\d{3}-\d{3}-\d{4}', '800-555-1212') # \d表明的是一個數字{3}表明的是前面的數字出現三次,也就是把800給匹配出來了,而後就是單純的一個-,後面的也是一個效果,組合起來就把電話號碼給匹配出來了。 <_sre.SRE_Match object; span=(0, 11), match='800-555-1212'>
>>>

# 4. 電子郵件地址xxx@yyy.com
>>> re.search('\w+@\w+\.com', 'hwt@qq.com') # 首先\w+匹配一個數字字母下劃線的字符串,而後一個單純的@,而後又是一個字符串, 以後\.由於作了轉義,表明的就是一個單純的. <_sre.SRE_Match object; span=(0, 10), match='hwt@qq.com'>
>>>

  【\s】匹配空格字符

>>> re.search('of\sthe', 'of the') # 就是匹配一個空格字符, 不管是換行符,\t\v\f都是能夠匹配到的 <_sre.SRE_Match object; span=(0, 6), match='of the'>
>>>

  【[a-b]】中括號表明a-b的一個範圍,表明的是從a-b的字符之間匹配一個字符

  應用一:建立字符串

>>> re.search('[A-Z]', 'D') # 匹配A-Z之間的一個字符,因此D就能夠匹配了,之間不能有空格 <_sre.SRE_Match object; span=(0, 1), match='D'>
>>>
>>> re.search('[ab][cd]', 'ac') # 從第一個方框中取出一個值與第二個方框中取出一個值進行組合,注意不能匹配到ab和cd,若是想匹配ab和cd須要經過擇一匹配符號也就是[|] <_sre.SRE_Match object; span=(0, 2), match='ac'>
>>> re.search('[ab][cd]', 'ad') <_sre.SRE_Match object; span=(0, 2), match='ad'>
>>> re.search('[ab][cd]', 'ac') <_sre.SRE_Match object; span=(0, 2), match='ac'>
>>> re.search('[ab][cd]', 'ad') <_sre.SRE_Match object; span=(0, 2), match='ad'>
>>>

  【[^ a -b]】匹配除了a-b以外的任何一個字符

# 1. z後面跟着任何一個字符而後再跟着一個0-9之間的數字
>>> re.search('z.[0-9]', 'z#0') <_sre.SRE_Match object; span=(0, 3), match='z#0'>
>>> re.search('z.[0-9]', 'z#1') <_sre.SRE_Match object; span=(0, 3), match='z#1'>
>>>

# 2. 除了aeiou以外的任何字符
>>> re.search('[^aeiou]', 's') <_sre.SRE_Match object; span=(0, 1), match='s'>
>>>

# 3. 除了製表符或者換行符以外的任何一個字符
>>> re.search('[^\n\t]', 'aljg') <_sre.SRE_Match object; span=(0, 1), match='a'>
>>>

第四類: 分組匹配

  分組匹配嚴格意義上來說並非一個匹配的元字符,由於它自己並不會影響匹配的結果,只是會把匹配的結果按照括號分開,而後存儲到必定的位置,便於咱們以後使用的。那爲何要有分組呢?由於在不少的時候咱們並非對於匹配出來的字符感興趣的,有時候咱們只是對於匹配字符的某一個塊感興趣,可能還會對這一塊進行一系列的操做。這就須要分組來幫咱們作這件事了。

  分組相對來講較爲簡單,可是卻至關重要,簡單在於它並不會影響咱們的匹配結果,重要在數據匹配以後大部分都要用到這個分組。

  【 () 】,在以後介紹group和groups的時候會提到

>>> import re >>> re.search('(\d+)([a-z])(\.)(\w+)', '123c.sleg234') # 這個和下面匹配的結果是同樣的,意思是加上括號分組的時候並不會對匹配的結果產生影響 <_sre.SRE_Match object; span=(0, 12), match='123c.sleg234'>  # 它只是經過分組給咱們返回了一系列的數據,咱們能夠經過group(s)方法得到而已
>>> re.search('\d+[a-z]\.\w+', '123c.sleg234')         <_sre.SRE_Match object; span=(0, 12), match='123c.sleg234'>
>>>

第五類:擇一匹配符

  【|】豎槓表明的是從幾個正則表達式中獲得一個

>>> re.search('ab|cd', 'ab') # 從左邊的ab和cd中匹配相應的數據,可是不會匹配ac,這也是和[]的區別 <_sre.SRE_Match object; span=(0, 2), match='ab'>
>>> re.search('ab|cd', 'cd') <_sre.SRE_Match object; span=(0, 2), match='cd'>
>>> re.search('ab|cd', 'ac') >>>

第六類:擴展表示法

  擴展表示法等以後真正用到了再回來看吧

  

三. python3re模塊方法

方法一: compile編譯

  程序是咱們寫出來的一堆字符串,計算機是看不懂的,所以想要讓咱們寫出來的代碼能夠正常的計算機中執行,就必須將代碼塊編譯成字節碼(也就是程序可以理解的語言)。而complie編譯就是這個原理,也就是我提早將字符串編譯成一個對象,以後你要進行使用的時候沒必要再進行編譯了,直接調用此對象就能夠了。對於只調用一次的正則表達式用不用此方法都是能夠的,可是對於那些須要調用屢次的正則表達式而言,提早編譯就可以大大的提高執行性能。complie方法就是爲了作這樣的一件事的。

>>> import re >>> s = '\d+' # 這個是本身寫的正則表達式
>>> int_obj = re.compile(s) # 經過complie方法將s編譯成對象,以後就直接能夠經過這個對象直接去調用方法,能夠節省性能 >>> print(int_obj.search('123')) <_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(int_obj.search('123')) <_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(int_obj.search('123')) <_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(int_obj.search('123')) <_sre.SRE_Match object; span=(0, 3), match='123'>
>>>

方法二:group 和 groups方法

  (1).group和groups方法都是在正則表達式匹配成功以後調用的方法,若是沒有匹配成功調用此方法會報錯

  (2).group方法會獲得一個以下的列表【當前匹配的字符串, 分組一,分組二........】沒有分組就只有一個元素

  (3).groups方法會獲得一個以下的元組 ( 分組一,分組二......), 沒有分組就是空空列表

  (4).這兩個方法只能是search和match成功匹配到的對象纔可使用。

以美國電話號碼匹配爲例s1 = '\d{3}-\d{3}-\d{4}'

(1).沒有分組的狀況下

>>> s1 = '\d{3}-\d{3}-\d{4}'  # 美國電話號碼的格式匹配正則表達式
>>> s2 = '(\d{3})-(\d{3})-(\d{4})'    # 將美國的電話號碼進行分組
>>> tel = '099-898-2392' # 這是一個電話格式
>>> re.search(s1, tel) # 以前沒有學group的時候咱們一直獲得的都是下面的這種對象 <_sre.SRE_Match object; span=(0, 12), match='099-898-2392'>
>>> re.search(s1, tel).group() # 獲得匹配的值 '099-898-2392'
>>> re.search(s1, tel).group(0) # 和上面的是同樣的,由於沒有分組獲得的列表中就只有一個元素 '099-898-2392'
>>> re.search(s1, tel).group(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: no such group >>> re.search(s1, tel).groups() # 沒有分組的狀況下groups就是空的元組 () >>>

(2)有分組的狀況下

>>> s1 = '\d{3}-\d{3}-\d{4}'  # 美國電話號碼的格式匹配正則表達式
>>> s2 = '(\d{3})-(\d{3})-(\d{4})'    # 將美國的電話號碼進行分組
>>> tel = '099-898-2392'
>>>
>>> print(re.search(s2, tel).group()) 099-898-2392
>>> print(re.search(s2, tel).group(0))  # 得到的是整個匹配的對象
099-898-2392
>>> print(re.search(s2, tel).group(1))  # 第一個子組099
099
>>> print(re.search(s2, tel).group(2))  # 得到的第二個子組898
898
>>> print(re.search(s2, tel).group(3))  # 得到的第三個子組2392
2392
>>> print(re.search(s2, tel).groups())  # 得到子組的一個列表
('099', '898', '2392') >>>

方法三:  match,search, findall

  match: 在字符串的開頭對寫的正則表達式進行匹配。 匹配成功,返回匹配對象,匹配失敗,返回None

  search:在整個字符串中對寫的正則表達式進行匹配。 匹配成功,返回第一個被匹配的對象,匹配失敗,返回None

  findall: 在整個字符串中對寫的正則表達式進行匹配。只要是匹配成功的就添加到列表中,最後返回一個列表

match:

>>> re.match('foo', 'food on the table').group()  # 從字符串開頭開始匹配,匹配到了foo,因此group獲得的是匹配到的foo
'foo'
>>> re.match('ood', 'food on the table')  # 從字符串開頭開始匹配,發現並非00d,因此沒有匹配到結果,返回一個空
>>>

search:

>>> re.match('foo', 'seafood')   # 字符串開頭並非foo,因此match沒有匹配到
>>> re.search('foo', 'seafood').group()   # search是在整個字符串中匹配的,因此
'foo'
>>>

findall:

>>> re.match('foo', 'seafood, seafood')   # 字符串開頭並非foo,因此沒有匹配
>>> re.search('foo', 'seafood, seafood').group()  # 在字符串匹配到第一個foo的時候就再也不進行匹配了
'foo'
>>> re.findall('foo', 'seafood, seafood')  # 在字符串給中查找到全部匹配到的字符串放在列表中
['foo', 'foo']
>>> 

方法四: finditer, findall

  finditer和findall做用實際上是同樣的,不一樣之處在於finditer返回的是一個迭代器(更加節省內存),而findall返回的是一個列表。

  (1).在沒有分組的狀況下,每個被匹配的元素都會做爲列表的元素

  (2).在分組的狀況下,被匹配的元素會把子組放在一個元組中放在列表中(比較繞,直接上例子)

(1)在沒有分組的狀況下

s = 'This and that.'
print(re.findall(r'Th\w+ and th\w+', s))   # 會把匹配到的信息一個一個的放在列表中,此處只是匹配了一個
print(re.finditer(r'Th\w+ and th\w+', s).__next__())  # iter返回一個迭代器,能夠經過__next__去得到第一個對象,注意此處是相似於match得到的對象
print(re.match('s', 's'))     # 爲了和上面進行對比的
# 結果:
# ['This and that']
# <_sre.SRE_Match object; span=(0, 13), match='This and that'>
# <_sre.SRE_Match object; span=(0, 1), match='s'>

(2)有分組的狀況

s = 'This and that.'
print(re.findall(r'(Th\w+) and (th\w+)', s))   # 有分組就會發現列表中其實放的並非匹配到的值了,而是子組元組
print(re.finditer(r'(Th\w+) and (th\w+)', s).__next__())  #可是iter獲得的仍是匹配的對象,若是想獲得子組能夠經過group去得到
print(re.match('s', 's'))     # 爲了和上面進行對比的

# 結果:
# [('This', 'that')]
# <_sre.SRE_Match object; span=(0, 13), match='This and that'>
# <_sre.SRE_Match object; span=(0, 1), match='s'>

方法五: sub

  sub將搜索匹配到的字符串替換成另一種字符串。

# 參數一: 正則表達式
# 參數二: 要替換的字符串
# 參數三: 源字符串
# 將替換好的字符串進行返回
s = re.sub('X', 'Mr. Smith', 'attn: X\n\nDear X, \n')
print(s)


#結果:
# attn: Mr. Smith
# 
# Dear Mr. Smith, 
# 參數一: 正則表達式
# 參數二: 要替換的字符串
# 參數三: 源字符串
# 將替換好的字符串進行返回
s = re.sub('[ae]', 'X', 'abcdef')
print(s)

# 結果:
# XbcdXf

例子: 將美式的日期表示法轉換成其餘國家的日期表示法

# 2/20/[1991|91]   月/日/年  美國
# 20/2/1991   日/月/年


# 首先先把美國的時間格式用正則表達式匹配到
m = '(\d{1,2})/(\d{1,2})/(\d{4}|\d{2})'
# 而後\N進行分組替換
s = re.sub(m, r'\2/\1/\3', '2/20/1991')
print(s)

方法六: split

  (1). 若是給定的模式不是特殊字符,那麼此方法和字符串的split是同樣的

  (2). 能夠經過設定一個max值來肯定須要分割幾回

  python核心編程中提示咱們: 能用字符串的split分割的儘可能不要使用影響性能的正則表達式進行分割。

print(re.split(':', 'str1:str2:str3'))

# 結果:
# ['str1', 'str2', 'str3']

 四. python3的re模塊練習

 練習一: 擇一匹配多個字符串

>>> # 擇一匹配
... bt = 'bat|bet|bit'
>>> print(re.match(bt, 'bt'))   # 由於此時的bt是擇一匹配,也就是隻能匹配bat或者bet或者bit字符串
None
>>> print(re.match(bt, 'he bit me'))  # 雖然字符串中有bit可是不是在開頭,因此匹配不到
None
>>> print(re.search(bt, 'he bit me').group())  # 這個search在整個字符串中進行查找,是能夠匹配到的
bit
>>> 

練習二: 使用【.】來匹配除了換行符之外的任意字符

>>> anyend = '.end'
>>> print(re.match(anyend, 'bend').group())   # .匹配了b
bend
>>> print(re.match(anyend, 'end'))   # 任意字符但不是沒有,因此沒有匹配到
None
>>> print(re.match(anyend, '\nend'))  # 任意的非換行符,因此沒有匹配到
None
>>> print(re.search(anyend, 'the end').group())  # 用search去匹配空格一個end
 end
>>> print(re.match('3.14', '3014').group())   # . 沒有加轉義符表明的是匹配任意的非換行符,因此能夠匹配到
3014 
>>> print(re.match('3\.14', '3.14').group())  # 這個.被轉義 了
3.14
>>>

練習三: 建立字符集的使用 【[ab][cd]】

>>> re.match('[c2][23][dp][o2]', 'c3po').group()  # 在正則表達式的每一個方框中隨機挑一個進行組合
'c3po'
>>> re.match('[c2][23][dp][o2]', 'c2do').group()
'c2do'
>>> re.match('r2d2|c3po', 'c2do')   # 擇一匹配只能是r2d2或者是c3po和建立字符集仍是有差異的
>>> re.match('r2d2|c3po', 'r2d2')
<_sre.SRE_Match object; span=(0, 4), match='r2d2'>
>>>

練習四: 重複匹配和分組

>>> # 郵件.com前面出現一個名稱
... mail1 = '\w+@\w+\.com'   # 能夠匹配相似於hello@xxx.com
>>> # 擴展一下,使得.com前面能夠出現一個或者兩個名稱
... mail2 = '\w+@(\w+\.)?\w+\.com'  # 能夠匹配相似於hello@www.xxx.com
>>>
>>> # 再擴展一下,使得.com前面能夠出現任意次數的名稱
... mail3 = '\w+@(\w+\.)*\w+\.com'
>>> re.match(mail1, 'nobody@xxx.com').group()
'nobody@xxx.com'
>>> re.match(mail2, 'nobody@www.xxx.com').group()
'nobody@www.xxx.com'
>>> re.match(mail1, 'nobody@www.xxx.com')
>>> re.match(mail3, 'nobody@aaa.www.xxx.com').group()
'nobody@aaa.www.xxx.com'
>>>

練習五:分組的使用

>>> re.match('(\w+)-(\d+)', 'abcde-123')   # 匹配字符串
<_sre.SRE_Match object; span=(0, 9), match='abcde-123'>
>>> re.match('(\w+)-(\d+)', 'abcde-123').group()  # 匹配完成以後用group()的到匹配的結果
'abcde-123'
>>> re.match('(\w+)-(\d+)', 'abcde-123').group(1)  # 用索引1獲得分組一,也就是第一個括號匹配的數據
'abcde'
>>> re.match('(\w+)-(\d+)', 'abcde-123').group(2)# 用索引2獲得分組二,也就是第二個括號匹配的數據
'123'
>>>

練習六: 位置匹配在python中的使用

>>> re.search('^The', 'The end.').group()   # ^表明起始位置
'The'
>>> re.search('^The', 'end. The')     # 不做爲起始地址
>>> re.search(r'\bThe', 'bite The Dog').group()   #The左邊是個邊界,直白講就是沒有英文字符
'The'
>>> re.search(r'\bThe', 'biteThe Dog')    # The左邊不是一個邊界,因此沒有匹配到
>>> re.search(r'\BThe', 'biteThe Dog').group()  # B表明的就是否是邊界的時候纔會被匹配
'The'
>>>

五. 第一章課後練習題

前期的準備:

生成一個用來做爲re練習的隨機字符串的代碼:

import random
from string import ascii_lowercase as lc
import sys
import time
tlds = ('com', 'edu', 'net', 'org', 'gov')
for i in range(random.randrange(5, 11)):
    dtint = random.randrange(sys.maxsize)
    dtstr = time.ctime(dtint)
    llen = random.randrange(4, 8)
    login = ''.join(random.choice(lc) for j in range(llen))
    dlen = random.randrange(llen, 13)
    dom = ''.join(random.choice(lc) for j in range(llen))
    msg = '%s::%s@%s.%s::%d-%d-%d\n' %(
        dtstr,
        login,
        dom,
        random.choice(tlds),
        dtint,
        llen,
        dlen
    )
    with open('redata.txt', 'at', encoding='utf-8') as f:
        f.write(msg)
生成隨機字符串

 知識點儲備一:找到時間戳中一週的第幾天

>>> # 示例一: 找到時間戳中一週的第幾天
... data = 'Wed Sep 16 11:17:21 1992::pscss@tdaja.org::716613441-5-6'
>>> # 經過擇一匹配把天天的單詞縮寫放在一個括號內,而後^表示的是一個單詞的起始
... # 可是有的地方天天的單詞縮寫並非這樣的,因此這樣子的正則表達式的適用性並非很強
... pattr1 = '^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)'
>>> print(re.search(pattr1, data).group())
Wed
>>> print(re.search(pattr1, data).group(1))
Wed
>>>
>>>
>>> # 所以下面的正則表達式的意思是任意的字母數字字符三個,可是注意寫成這樣'^(\w){3}'是有問題的
... pattr2 = '^(\w{3})'
>>> print(re.search(pattr2, data).group())
Wed
>>> print(re.search(pattr2, data).group(1))
Wed
>>>
>>>
>>> # 注意寫成這樣是有問題的
... # 由於將{3}寫在括號外部表明的是分組只有一個字符那就是\w,所以在匹配的過程當中分組的值是在不停的更新迭代的,最後變成三個字符中的最後一個
... # 啓發: 咱們分組想要什麼樣的值,就把()放在哪裏。
... pattr3 = '^(\w){3}'
>>> print(re.search(pattr3, data).group())
Wed
>>> print(re.search(pattr3, data).group(1))
d
>>>

 知識點儲備二: 貪婪匹配

# 示例二:想獲得由三個連字符分隔的整數
data = 'Wed Sep 16 11:17:21 1992::pscss@tdaja.org::716613441-5-6'

# 經過這樣的方式咱們能夠匹配到,可是隻能稱之爲搜索,咱們每每須要作的是匹配整個字符串,而後經過分組的形式得到咱們須要的值
pattr1 = '\d+-\d+-\d+'
print(re.search(pattr1, data).group())

# .+ 任意字符出現至少一次,所以匹配到了三個連字符整數的前面,以後經過後面的匹配整數,這樣就實現了對整個字符串的匹配
# 而後經過分組得到咱們須要的值
pattr2 = '.+(\d+-\d+-\d+)'
# 當咱們要得到分組的時候卻發現此時的值並非咱們想要的,這是由於貪婪匹配的緣由
# .+ 或匹配符合它要求的全部字符串,而後纔會給後面的正則表達式進行匹配
print(re.search(pattr2, data).group(1))


# 咱們能夠經過?來結束貪婪匹配
pattr3 = '.+?(\d+-\d+-\d+)'
print(re.search(pattr3, data).group(1))


# 結果:
# 716613441-5-6
# 1-5-6
# 716613441-5-6

做業題:

import re
# 1-1 識別後續的字符串:「bat」、「bit」、「but」、「hat」、「hit」或者「hut」。
print(re.search('[bh][aiu]t', 'hut').group())
# 1-2 匹配由單個空格分隔的任意單詞對,也就是姓和名。
print(re.search(r'\b[a-zA-Z]+\s[a-zA-Z]+\b', 'Tom Jerry Hello Bye House Good God').group())
# 1-3 匹配由單個逗號和單個空白符分隔的任何單詞和單個字母,如姓氏的首字母。
print(re.search(r'\w+,\s\w+', 'a, b').group())
# 1-4 匹配全部有效 Python 標識符的集合。
print(re.search(r'^[a-zA-Z_]\w*', 'hello_world1_').group()) # 此處寫的是python的有效變量名的正則表達式
# 1-5 根據讀者當地的格式,匹配街道地址(使你的正則表達式足夠通用,來匹配任意數量的街道單詞,包括類型名稱)。
# 例如,美國街道地址使用以下格式: 1180 Bordeaux Drive。使你的正則表達式足夠靈活, 以支持多單詞的街道名稱,如 3120 De la Cruz Boulevard。
print(re.search(r'^\d+(\s\w+)*', '3120 De la Cruz Boulevard').group())
# 1-6 匹配以「www」起始且以「.com」結尾的簡單 Web 域名;例如, www://www. yahoo.com/。
# 選作題: 你的正則表達式也能夠支持其餘高級域名,如.edu、 .net 等(例如,http://www.foothill.edu)。
print(re.search('^w{3}.*\.(com|edu|net)', 'www.foothill.edu.com').group())
# 1-7 匹配全部可以表示 Python 整數的字符串集。python3中已經再也不區分整形和長整形了
print(re.search(r'^0$|(^-?[1-9]\d*$)', '-2147483647').group())  # python中浮點數點是確定要有的
# 1-9 匹配全部可以表示 Python 浮點數的字符串集。 .23和1.都是正確的?,三種狀況,前面
print(re.match(r'(^\d+\.\d*$)|(^\d*\.\d+$)|(^\d+\.\d+$)', '09.23238').group())
# 1-10 匹配全部可以表示 Python 複數的字符串集。
# 1+2j  -j  +j  寫出來的也只能知足一部分吧
print(re.search(r'(\d+\.?\d*[+-]?\d+\.?\d*j)|([+-]?\d+\.?\d*j)', '-2.2j').group())
# 1-11 匹配全部可以表示有效電子郵件地址的集合(從一個寬鬆的正則表達式開始,而後嘗試使它儘量嚴謹,不過要保持正確的功能
print(re.search('\w+@\w+\.\w+\.com', '18279159836@hwt.163.com').group())
print(re.search('\w+@(\w+\.)+\w+\.(com|edu|org)', '18279159836@hwt.163.com').group())
# 1-12 匹配全部可以表示有效的網站地址的集合(URL)(從一個寬鬆的正則表達式開始,而後嘗試使它儘量嚴謹,不過要保持正確的功能)。
print(re.search('^(https?//:)?(w{3}\.)?.*\.\w{3}', 'https://www.lsejg.lwegfoothill.edu.com').group())
"""
1-13 type()。 內置函數 type()返回一個類型對象,以下所示,該對象將表示爲一個Pythonic類型的字符串。
>>> type(0)
<type 'int'>
>>> type(.34)
<type 'float'>
>>> type(dir)
<type 'builtin_function_or_method'>
建立一個可以從字符串中提取實際類型名稱的正則表達式。函數將對相似於<type'int' >的字符串返回 int(其餘類型也是如此,如 'float' 、 'builtin_function_or_method' 等)。
注意: 你所實現的值將存入類和一些內置類型的__name__屬性中。
"""
print(re.search(r"^<type\s*'([a-zA-Z_]+)'\s*>$", "<type 'builtin_function_or_method'>").group(1))
# 1-14 處理日期。1.2 節提供了來匹配單個或者兩個數字字符串的正則表達式模式,來表示 1~9 的月份(0?[1-9])。建立一個正則表達式來表示標準日曆中剩餘三個月的數字。
print(re.search('1[0-2]', '10').group())
'''
1-15 處理信用卡號碼。 1.2 節還提供了一個可以匹配信用卡(CC)號碼([0-9]{15,16})的正則表達式模式。然而,該模式不容許使用連字符來分割數字塊。
建立一個容許使用連字符的正則表達式,可是僅能用於正確的位置。例如, 15 位的信用卡號碼使用 4-6-5 的模式,代表 4 個數字-連字符-6 個數字-連字符-5 個數字; 16 位的
信用卡號碼使用 4-4-4-4 的模式。記住, 要對整個字符串進行合適的分組。 
選作題:有一個判斷信用卡號碼是否有效的標準算法。編寫一些代碼,這些代碼不但可以識別具備正確格式的號碼, 並且可以識別有效的信用卡號碼。
'''
print(re.search('([0-9]{4}-[0-9]{6}-[0-9]{5})|([0-9]{4}-[0-9]{4}-[0-9]{4}-[0-9]{4})', '0000-0923-0099-8899').groups())
1-15題附答案
# 1-17 判斷在 redata.tex 中一週的每一天出現的次數(換句話說,讀者也能夠計算所選擇的年份中每月中出現的次數)。
# 分析,由於咱們只須要一週的每一天,所以咱們只須要獲得前面的時間戳就ok了,後面直接.*匹配
import re
file_path = 'redata.txt'
pattr = '^(\w{3}).*'
week = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
week_dict = {key: 0 for key in week}
print(week_dict)
with open(file_path, 'rt', encoding='utf-8') as f:
    obj_list = [re.search(pattr, each_line.rstrip('\n')) for each_line in f]
for obj in obj_list:
    if obj.group(1) in week_dict:
        week_dict[obj.group(1)] += 1
# print展現打印計算出來的結果
for key, value in week_dict.items():
    print(key + '---->' + str(value))
1-17題
# 1-18 經過確認整數字段中的第一個整數匹配在每一個輸出行起始部分的時間戳,確保在redata.txt 中沒有數據損壞。
import re

#Sun Mar  2 03:01:14 1997::akofd@sovto.gov::857242874-5-10
file_path = 'redata.txt'
pattr = '^.*?(\d+\s\d{2}:\d{2}:\d{2}\s\d{4}).*'
with open(file_path, 'rt', encoding='utf-8') as f:
    for each_line in f:
        print('時間戳爲: ', re.search(pattr, each_line.rstrip('\n')).group(1))
1-18題
import re

data = 'Sun Mar  2 03:01:14 1997::akofd@sovto.gov::857242874-5-10'
# 建立如下正則表達式。
# 1-19 提取每行中完整的時間戳。
pattr = '^.*?(\d+\s\d{2}:\d{2}:\d{2}\s\d{4}).*'
# 1-20 提取每行中完整的電子郵件地址。
print(re.search(r'^.*?::(\w+@\w+\.(com|edu|net|org|gov)).*', data).group(1))
# 1-21 僅僅提取時間戳中的月份
print(re.search(r'^\w{3}\s(\w{3}).*', data).group(1))
# 1-22 僅僅提取時間戳中的年份。
print(re.search(r'.*?(\d{4}).*', data).group(1))
# 1-23 僅僅提取時間戳中的時間(HH:MM:SS)。
print(re.search(r'.*?(\d{2}:\d{2}:\d{2}).*', data).group(1))
# 1-24 僅僅從電子郵件地址中提取登陸名和域名(包括主域名和高級域名一塊兒提取)。
print(re.search(r'.*?@(\w+\.(com|edu|net|org|gov)).*', data).group(1))
# 1-25 僅僅從電子郵件地址中提取登陸名和域名(包括主域名和高級域名)。
print(re.search(r'.*?@(\w+)\.(com|edu|net|org|gov).*', data).group(1))
print(re.search(r'.*?@(\w+)\.(com|edu|net|org|gov).*', data).group(2))
1-19到1-25題
import re
# 1-26 使用你的電子郵件地址替換每一行數據中的電子郵件地址。
with open('redata.txt', 'rt', encoding='utf-8') as f_read, \
        open('redata.txt.bc', 'wt', encoding='utf-8') as f_write:
    for each_line in f_read:
        f_write.write(re.sub(
            r'(.*?::)(\w+@\w+\.(com|edu|net|org|gov))(.*)',
            r'\1(18279159836@163.com)\4',
            each_line.strip('\n')
        ) + '\n')
import os
os.remove('redata.txt')
os.rename('redata.txt.bc', 'redata.txt')
1-26使用你的電子郵件地址替換每一行數據中的電子郵件地址
import re
# 1-27 從時間戳中提取月、日和年,而後以「月,日,年」的格式,每一行僅僅迭代一次。
with open('redata.txt', 'rt', encoding='utf-8') as f_read, \
        open('redata.txt.bc', 'wt', encoding='utf-8') as f_write:
    for each_line in f_read:
        f_write.write(re.sub(
            r'^(\w{3})(\s)(\w{3})(.*)(\d{4})(.*)',
            r'\3\2\1\4\5\6',
            each_line.strip('\n')
        ) + '\n')
import os
os.remove('redata.txt')
os.rename('redata.txt.bc', 'redata.txt')
1-27 從時間戳中提取月、日和年,而後以「月,日,年」的格式
import re

# 處理電話號碼。對於練習 1-28 和 1-29,回顧 1.2 節介紹的正則表達式\d{3}-\d{3}-\d{4},它匹配電話號碼,可是容許可選的區號做爲前綴。更新正則表達式,使它知足如下條件。
# 1-28 區號(三個整數集合中的第一部分和後面的連字符)是可選的,也就是說,正則表達式應當匹配 800-555-1212, 也能匹配 555-1212。

print(re.search('(\d{3}-)?\d{3}-\d{4}', '555-1212').group())
# 1-29 支持使用圓括號或者連字符鏈接的區號(更不用說是可選的內容);使正則表達式匹配 800-555-12十二、 555-1212 以及(800) 555-1212。
print(re.search('((\d{3}-)?|\(\d{3}\))\s?\d{3}-\d{4}', '(800)555-1212').group())
1-28到1-29題
# 正則表達式應用程序。下面練習在處理在線數據時生成了有用的應用程序腳本。
# 1-30 生成 HTML。提供一個連接列表(以及可選的簡短描述),不管用戶經過命令
# 行方式提供、 經過來自於其餘腳本的輸入,仍是來自於數據庫, 都生成一個
# Web 頁面(.html),該頁面包含做爲超文本錨點的全部連接, 它能夠在 Web 瀏
# 覽器中查看,容許用戶單擊這些連接,而後訪問相應的站點。若是提供了簡短
# 的描述,就使用該描述做爲超文本而不是 URL。
# 1-31 tweet 精簡。有時候你想要查看由 Twitter 用戶發送到 Twitter 服務的 tweet 純文本。
# 建立一個函數以獲取 tweet 和一個可選的「元」標記,該標記默認爲 False,然
# 後返回一個已精簡過的 tweet 字符串,即移除全部無關信息,例如,表示轉推的
# RT 符號、前導的「.」符號,以及全部#號標籤。若是元標記爲 True,就返回一
# 個包含元數據的字典。 這能夠包含一個鍵「RT」, 其相應的值是轉推該消息的用
# 戶的字符串元組和/或一個鍵「#號標籤」(包含一個#號標籤元組)。若是值不存
# 在(空元組), 就不要爲此建立一個鍵值條目。
# 1-32 亞馬遜爬蟲腳本。建立一個腳本,幫助你追蹤你最喜歡的書,以及這些書在亞馬
# 遜上的表現(或者可以追蹤圖書排名的任何其餘的在線書店)。例如,亞馬遜對於
# 任何一本圖書提供如下連接: http://amazon.com/dp/ISBN(例如, http://amazon.com/
# dp/0132678209)。讀 者能夠改變域名,檢查亞馬遜在其餘國家的站點上相同的圖
# 書排名,例如德國(.de)、 法國(.fr)、 日本(.jp)、 中國(.cn) 和英國(.co.uk)。
# 使用正則表達式或者標記解析器,例如 BeautifulSoup、 lxml 或者 html5lib 來解析
# 排名,而後讓用戶傳入命令行參數,指明輸出是否應當在一個純文本中,也許包
# 含在一個電子郵件正文中,仍是用於 Web 的格式化 HTML 中。
後面的三個題尚未學到前端,以後回來作

六. re模塊綜合應用之計算器

參考博客:http://www.cnblogs.com/wupeiqi/articles/4949995.html

 1. 計算器程序的邏輯圖

2. 計算器的正則表達式

(1).遞歸去括號正則表達式的一步一步詳細的解釋

# 匹配數字的正則表達式,能夠匹配到1, -1, -1.1, 1.1
r'-?\d+\.*\d*'
# 首先應該匹配一對括號,括號不能包括括號
r'\(\)'
# 而後咱們不是匹配空括號的,括號內要須要表達式的,表達式就須要加減乘除,可是加減乘除中特殊字符,所以咱們把它轉義一下
r'\([\+\-\*\/]\)'
# 匹配完操做符以後,就須要匹配數字了,將上面的匹配數字的正則表達式也放過來,可是這樣的表達式只能匹配到帶有加減乘除操做符的表達式
r'\([\+\-\*\/]-?\d+\.*\d*\)'
# 所以咱們再[]後面加上*以後,就能夠匹配到單純的數字了
r'\([\+\-\*\/]*-?\d+\.*\d*\)'
# 大概的步驟都已經完成了,可是上面的操做是匹配不到'(1-2)'這樣的字符串的,這是由於表達式只匹配了一次,而一個整數也是一個表達式
# 因此匹配不到,須要修改爲下面這個樣子
r'\(([\+\-\*\/]*-?\d+\.*\d*){2,}\)'

(2)遞歸乘除正則表達式詳解

# r'\d+\.*\d*[*/]-?\d+\.*\d*'

# 乘除的表達式比較簡單,把正則表達式拆成三個部分
# 1. 乘除前面的是一個數字
 r'\d+\.*\d*'
# 2. 乘除後面的也是一個數字,只不事後面的數字必需要匹配一個-,爲的是匹配5 * -4這樣的表達式
r'-?\d+\.*\d*'
# 3. 就是乘除符號了

遞歸加減的正則表達式和乘除的正則表達式思惟是同樣的,這裏就再也不贅述了

import re
import time


def computer_add_subtract(expression):
    """計算表達式中的加減法,而後將表達式中的值返回

    expression: 只有加減法的表達式
    """
    # 由於在乘除運算的時候會多出來不少的+-號,所以應該先把加減號進行合併
    while re.search('(\-\-)|(\+\+)|(\+\-)|(\-\+)', expression):
        expression = re.sub('\-\-', '+', expression)
        expression = re.sub('\+\+', '+', expression)
        expression = re.sub('\+\-', '-', expression)
        expression = re.sub('\-\+', '-', expression)
    content = computer_add_subtract_repr_obj.search(expression)
    if not content:
        return expression

    # 分割
    before, after = computer_add_subtract_repr_obj.split(expression, 1)
    # before, after = re.split(pattr, expression, 1)

    # 計算得到的值, 首先匹配相應的表達式,而後根據分組得到相應的值
    content = re.search('(\-?\d+\.*\d*)([+-])(\-?\d+\.*\d*)', content.group()).groups()
    if '+' == content[1]:
        result = float(content[0]) + float(content[2])
    else:
        result = float(content[0]) - float(content[2])
    # 拼接字符串
    new_expression = '%s%s%s' % (before, result, after)
    return computer_add_subtract(new_expression)


def computer_multiply_divide(expression):
    """計算表達式中乘除法,而後將從新拼接的字符串進行返回

    expression: 表達式
    """
    content = computer_multiply_divide_repr_obj.search(expression)
    if not content:
        return expression

    # 分割字符串
    before, after = computer_multiply_divide_repr_obj.split(expression, 1)

    # 得到表達式
    content = content.group()
    # 判斷是乘仍是除法
    if '*' in content:
        result = float(content.split('*')[0]) * float(content.split('*')[1])
    else:
        result = float(content.split('/')[0]) / float(content.split('/')[1])

    # 拼接字符串
    new_expression = '%s%s%s' % (before, result, after)
    return computer_multiply_divide(new_expression)


def compute(expression):
    """計算沒有括號的表達式的值

    expression: 表達式
    """
    # 先計算乘除法
    temp_str = computer_multiply_divide(expression)
    # 乘除法計算完成以後返回的表達式就只有加減了,能夠傳遞給加減的函數進行計算
    result = computer_add_subtract(temp_str)
    # 最後返回結果
    return result


def deal_parentheses(expression):
    """遞歸處理掉整個表達式中的括號

    expression: 傳入的表達式
    """
    pattr = r'\(([+\-*/]*\d+\.*\d*){2,}\)'
    # 判斷表達式中有沒有括號
    content = re.search(pattr, expression)
    if not content:
        return compute(expression)

    # 分割得到表達式的前面部分和後面部分,只是不太明白爲何這個地方爲何分割出來以後是3個值
    before, nothing, after = re.split(pattr, expression, 1)

    # 得到表達式以後去括號並計算相應的值
    content = content.group()
    content = content[1:-1]
    result = compute(content)

    # 拼接出新的表達式
    new_expression = '%s%s%s' % (before, result, after)
    return deal_parentheses(new_expression)


def calculator(expression):
    """計算器主程序

    expression: 用戶輸入的表達式
    """
    print('請稍等,正在計算....')
    expression = re.sub('\s+', '', expression)
    start = time.time()
    res = deal_parentheses(expression)
    end = time.time()
    print('結果爲>>', res, '時間爲>>', end - start)


if __name__ == '__main__':
    deal_parentheses_repr_obj = re.compile(r'\(([+\-*/]*\d+\.*\d*){2,}\)')
    computer_multiply_divide_repr_obj = re.compile(r'\d+\.*\d*[*/]-?\d+\.*\d*')
    computer_add_subtract_repr_obj = re.compile('\-?\-?\d+\.*\d*[\+\-]-?\d+\.*\d*')

    input_expression = '1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
    # input_expression = '1-2*-30/-12*(-20+200*-3/-200*-300-100)'
    calculator(input_expression)
計算機源代碼
相關文章
相關標籤/搜索