---
slideOptions:
transition: slide
tags: 程式線107上
---
# Regular Expression
[TOC]
---
練習網站
http://www.rubular.com/
---
HackerSir
`a`
<span>H==a==ckerSir<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
HackerSir
`ker`
<span>Hac==ker==Sir<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`.`
代表任意字元
(不包含`\n`)
<span>如果用剛剛的網站直接打`.`的話他會全選,但是用 python 他只會選一個字<!-- .element: class="fragment" data-fragment-index="1" --></span>
note: 如果選的字裡面有點要用`\`
----
HackerSir
`H.`
<span>==Ha==ckerSir<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`[ ]`
選多個字元
----
HackerSir
`[abcdefgh]`
<span>H==ac==k==e==rSir<!-- .element: class="fragment" data-fragment-index="1" --></span>
----
HackerSir
`[a-h]`
<span>H==ac==k==e==rSir<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`^`
代表不要
>注意:在`[ ]`裡面才是
----
HackerSir
`[^a-h]`
<span><p>==H==ac==k==e==rSir==</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
---
縮寫
+ `\d` = `[0-9]`
+ `\w` = `[A-Za-z0-9_]` **注意有底線**
+ `\s` = `[\t\s\r]`
+ `\D` = `[^\d]`
+ `\W` = `[^\w]`
+ `\S` = `[^\s]`
---
`*`
代表任意次數
----
HackerSir
`c.*`
<span><p>Ha==ckersir==</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`+`
代表至少一次
>他是跟著前面那個字的
----
banana
`n+a`
<span><p>ba==nana==</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
note: 想成他是要找a然後前面的n至少要一次
---
`?`
代表零或一次
>他是跟著前面那個字的
----
banana
`n?a`
<span><p>b==anana==</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
note: 想成他是要找a然後前面的n可有可無
---
`{次數}`
`{最少次數, 最多次數}`
----
Hello world.
`l{2}`
<span>He==ll==o world.<!-- .element: class="fragment" data-fragment-index="1" --></span>
----
Hello world.
`l{1,}`
<span>He==ll==o wor==l==d.<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
## 貪婪匹配
剛剛講的 `*` `+` `?` `{次數}`
都是屬於貪婪匹配
他在配對的時候會盡量多找
----
HackerSir
`H.*r`
<span>==HackerSir==<!-- .element: class="fragment" data-fragment-index="1" --></span>
note: `*`在配對的時候會一值往後找,導致後面他會被全選
----
HackerSir
`H.*?r`
<span>==Hacker==Sir<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`|`
或
----
iOS and android
`and|android`
我們預期他會是 iOS ==and android==
<span>**但這是錯的**<!-- .element: class="fragment" data-fragment-index="1" --></span>
----
iOS and android
`and|android`
<span>iOS ==and and==roid<!-- .element: class="fragment" data-fragment-index="1" --></span>
----
iOS and android
`android|and`
<span><p>iOS ==and android==</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`^`
開頭
----
hello hello
`^he`
<span>==he==llo hello<!-- .element: class="fragment" data-fragment-index="1" --></span>
---
`$`
結尾
----
hello hello
`llo$`
<span><p>hello he==llo==</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
---
# python 實作
---
`import re`
[官方文檔](https://docs.python.org/3.6/library/re.html)
note: 左上角可以選版本
---
`re.search(正則表達式, 字, (flags))`
掃描整個字串,return 第一個成功的
如果找不到, `return None`
<span><p>這裡的 return 不是直接丟字串給你</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
----
| flags | 說明 |
| -------- | -------- |
| `re.I` | 忽略大小寫 |
| `re.L` | 表示特殊字符 |
| `re.M` | 多行模式 |
| `re.S` | 讓 `\.` 包含換行 |
| `re.U` | 表示特殊字符 |
| `re.X` | 忽略空格和註解 |
----
`group( )`
`groups( )`
----
```python=
import re
s = '123asd789'
m = re.search("([0-9]*)([a-z]*)([0-9]*)",s)
print(m.groups())
print(m.group())
print(m.group(1))
print(m.group(2))
print(m.group(3))
```
>('123', 'asd', '789')
>123asd789
>123
>asd
>789
---
`re.match(正則表達式, 字, (flags))`
從**第一個字開始**,return第一個成功的
如果找不到, `return None`
<span><p>所以不是從第一個字開始,就會失敗</p><!-- .element: class="fragment" data-fragment-index="1" --></span>
----
`re.fullmatch(正則表達式, 字, (flags))`
從**第一個字開始**,**全部**成功才 return
---
`re.findall(正則表達式, 字, (flags))`
掃描整個字串,return一個list
note: 我最常用這個,因為能直接拿
----
```python=
import re
s = "hello hello"
m = re.findall("l", s)
print(m)
```
>['l', 'l', 'l', 'l']
---
`re.sub(正則表達式, 要換的字, 原本的字, (更換次數), (flags))`
掃描整個字串,並替換
----
```python=
import re
s = "hello hello"
m = re.sub("[hl]", 'w', s, 3)
print(m)
```
---
# 練習
---
## 練習第一題
字串:Minions love banana.
輸出:['ni', 'ns']
----
解答:
```python=
import re
s = 'Minions love banana.'
m = re.findall("n[is]", s)
print (m)
```
---
## 練習第二題
驗證身分證格式是否正確(不須驗證內容)
身份證字號格式:
第一碼:A-Z(大寫英文)
第二碼:1(男)或2(女)
後八碼:0-9(數字)
**不要給我用一堆if硬幹**
----
範例:
![](https://i.imgur.com/ZbsIe5E.png)
----
解答:
```python=
import re
while (1):
s = input('請輸入身份證字號:')
o = re.fullmatch("^[A-Z][12][0-9]{8}$", s)
if s == 'end':
break
elif o != None:
print('Ture')
else:
print('False')
```
---
## 練習第三題
驗證email格式
email格式:
英文或數字 + @ + 英文.英文(.英文)
----
範例:
![](https://i.imgur.com/gJxIqzU.png)
----
解答:
```python=
import re
while (1):
s = input('請輸入email:')
o = re.fullmatch("[a-zA-Z0-9]*\@[a-z]*\.[a-z]*\.?[a-z]{0,}", s)
if s == 'end':
break
elif o != None:
print('Ture')
else:
print('Flase')
```
---
## 練習第四題
請輸入一個由a、b、c組成的字串
並判別a是否出現偶數次
----
解答:
```python=
import re
a = input('輸入:')
b = re.findall('a', a)
if len(b) % 2 == 0:
print('Ture')
else:
print('False')
```
---
## 練習第五題
請輸入一個由a、b、c組成的字串
並判別不含子字串ab
----
解答:
```python=
import re
a = input('輸入:')
b = re.findall('ab', a)
if len(b) == 0:
print('Ture')
else:
print('Flase')
```
---
## 練習第六題
請輸入二進制數,並判別是否為4的倍數
(用re.match寫)
----
解答:
```python=
import re
text = input("請輸入二進制數,並判別是否為4的倍數:\n")
if re.match(r'^1[01]*00$',text):
print('True')
else:
print('Flase')
```
---
## 練習第七題
修改html的標籤
用visual studio code
把\<p>\</p>改成\<h3>\</h3>
```htmlmixed
<!DOCTYPE html>
<html>
<body>
<div style="background-color:black;color:white;padding:20px;">
<h2>London</h2>
<p>Hello</p>
<p>asdfg</p>
</div>
</body>
</html>
```
---
## 練習第八題
黑客社CTF
https://ctf.hackersir.org
![](https://i.imgur.com/21UGExp.png =550x)
---
## 補充
## sscanf( )
---
`%8s`
讀8個字
---
`%[^字元]`
到這個字元為止
---
`%[1-9]`
只讀1到9
---
`%*`
捨棄掉
---
```c=
#include<stdio.h>
int main(){
int a, b;
sscanf("-70x^8", "%dx%*1s%d", &a, &b);
printf("%d\n%d", a, b);
return 0;
}
```
>-70
>8
<!-- --- -->
<!-- [去年的教學影片](https://youtu.be/vYGERshoBdQ) -->