---
# System prepended metadata

title: 第十八天 Regular Expression正規表達式
tags: [R & python, Python_30]

---

---
disqus: ahb0222
GA : G-CQ4L16KHK4
---
# 第十八天 Regular Expression正規表達式
> [color=#40f1ef][name=LHB阿好伯, 2021/01/03][:earth_africa:](https://www.facebook.com/LHB0222/)
###### tags: `Python_30` `R & python`

![](https://i.imgur.com/DSYvcuu.jpg)



[TOC]

正則表達式或RegEx是一種特殊的文本字符串
有助於查找數據中的規則
RegEx可用於檢查其他數據類型中是否存在某些規則
python中使用 **`re`** 套件執行相關功能

```
import re
```

在正式學習之前，先了解一下原生字串
在Python中，表示原生字串，需要在字串前面加上r
例如在使用到上引號 ==\'== 或是反斜線 ==\\== 在程序中會造成錯誤
如果希望字串中 ==\'== 或 ==\\== 可以正常運行需要在字串前面加上r

# 建立re正規表達式物件re.compile()
這邊我想先以re.compile()建立re物件的方式去進行字串搜尋
主要是參考[Python 自動化的樂趣：搞定重複瑣碎&單調無聊的工作(第二版)](https://www.books.com.tw/exep/assp.php/gtgrthrst4577/products/0010867440?utm_source=gtgrthrst4577&utm_medium=ap-books&utm_content=recommend&utm_campaign=ap-202104)的方式來學習

## 搜尋數字 ==\\d== | ==[0-9]==
在正規表達式中\\d代表為0-9的數字也可以表達為[0-9]

```python=
import re
namRegex = re.compile(r'\d') #建立re物件
mo = namRegex.search('a1')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'1'
:::

若是覺得上面的公式太冗長也可以縮減為
```python=
re.search(r'\d','a1').group()
```


### 符合多次 ==*== | ==+== | =={}== 
常見的資料中我們若是想要在字串中尋找像是手機號碼
我們就可以使用 \\d來搜尋
我們知道手機號碼都是以09做開頭接上後面八位數
```python=
import re
namRegex = re.compile(r'09\d\d\d\d\d\d\d\d') #建立規則
mo = namRegex.search('我的手機號 0912345678....')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'0912345678'
:::
但這樣\\d就需要寫8次很冗長
此時我們就可以使用星號 ==*== 告訴電腦符合0次或多次皆可
或是使用加號 ==+== 符合1次或多次皆可
```python=
import re
namRegex = re.compile(r'09\d+') #建立規則
mo = namRegex.search('我的手機號 0912345678....')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'0912345678'
:::

但這樣又有可能遇到取得錯誤的資料問題
```python=
namRegex = re.compile(r'09\d*') #建立規則
mo = namRegex.search('家裡電話01-2165409....')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'09'
:::
這時候我們就可以使與用大括號 =={min,max}== 來限制我們要的重複數量
```python=
import re
namRegex = re.compile(r'09\d{8}') #建立規則
mo = namRegex.search('家裡電話01-2165409....')   #搜尋相符資料
mo.group()   #回傳相符資料
```

:::success
AttributeError: 'NoneType' object has no attribute 'group'
:::

### 貪婪模式 ==?==

在使用到 ==*== | ==+== | =={}== 時可能會遇到字串中有符合的結果不只一個
例如在前面提到大括弧可以設定符合的次數
設定最大與最小次數
但在正規表達式中預設會比對符合最大的符合資料
```python=
import re
namRegex = re.compile(r'\d{6,7}') #建立規則
mo = namRegex.search('12345678')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'1234567'
:::

```python=
import re
namRegex = re.compile(r'\d{6,7}?') #?貪婪模式
mo = namRegex.search('12345678')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'123456'
:::
#### 符合零次或一次 ==?==
==?== 也可以作為符合零次或一次使用
所以使用上需注意


## 分組查詢 ==()== 、 字元集合 ==[]==
在Python中可以選擇使用括號將想比對的資料做分組
例如我們市話號碼主要會有一個2 ~ 4碼的區碼加上6 ~ 8碼的數字所組成
若是我們想將兩組號碼區分開來這時候就需要使用到括號

>[長途電話區號表](https://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E9%95%B7%E9%80%94%E9%9B%BB%E8%A9%B1%E5%8D%80%E8%99%9F%E8%A1%A8)

```python=
import re
namRegex = re.compile(r'(\d{2,4})-(\d{6,8})') #建立規則
mo = namRegex.search('家裡電話01-2165409....')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'01-2165409'
:::
```python=+
mo.group(1)   #回傳第一組相符資料
```
:::success
'01'
:::
```python=+
mo.group(2)   #回傳第二組相符資料
```
:::success
'2165409'
:::

更進一步有時候我們收到的資料可能會是使用國際號碼
這時候若是兩種資料我們都想要
那就可以使用中括弧設定特定的集合來選擇我們需要的資料

```python=
import re
namRegex = re.compile(r'(\+*[886,0]\d{1,3})-(\d{6,8})')
mo = namRegex.search('家裡電話+8861-2165409....')   #搜尋相符資料
mo.group(1)   #回傳區碼資料
```
:::success
'+8861'
:::

剩下還有許多的規則若是有興趣可以查看維基百科中的[正規表示式](https://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F)寫的也很詳細


# 相關函數
```python=
re.match()：僅在字符串第一行的開頭搜索，如果找到則返回匹配的對象，否則不返回。
re.search()：如果字符串中的任何地方（包括多行字符串）都存在一個匹配對象，則返回一個匹配對象。
re.findall()：返回包含所有匹配項的列表
re.split()：獲取一個字符串，在匹配點處將其拆分，然後返回一個列表
re.sub()：替換字符串中的一個或多個匹配項
```

# 尋找相符字串re.match & re.search()

:::danger
re.match(要搜尋的規則, 目標字串, re.I)
re.I是忽略大小寫(re.IGNORECASE的縮寫)
:::

```python=
import re
txt = 'I love to teach R and python'
match = re.match('I LOVE TO TEACH', txt, re.I)
print(match)
```

:::success
<re.Match object; span=(0, 15), match='I love to teach'>
:::

# 使用多行註解模式_re.X
而使用re.X會開啟「詳細(verbose)模式」
之後就可以使用多行字串加上註釋會忽略空白
```python=
import re
namRegex = re.compile(r"""
(\d{2,4})  #開頭為2~4碼數字
-  #中間有一個減號
(\d{6,8})  #最後有6~8碼數字
""",re.X) #最後再加上re.X
mo = namRegex.search('家裡電話01-2165409....')   #搜尋相符資料
mo.group()   #回傳相符資料
```
:::success
'01-2165409'
:::


# R語言
R與研究不得不介紹strings套件了
但這部分就留到下次再來分享
不然篇幅真的太大了
https://evoldyn.gitlab.io/evomics-2018/ref-sheets/R_strings.pdf


# [好用的線上測試網站_regex101](https://regex101.com/)

![](https://i.imgur.com/8C3UFD2.png)

# [Rstudio好用正規表達式套件_remotes](https://github.com/gadenbuie/regexplain)

![](https://i.imgur.com/34aWL2x.png)

# 參考資料
https://github.com/Asabeneh/30-Days-Of-Python/blob/master/18_Day_Regular_expressions/18_regular_expressions.md
[Python 自動化的樂趣：搞定重複瑣碎&單調無聊的工作(第二版)](https://www.books.com.tw/exep/assp.php/gtgrthrst4577/products/0010867440?utm_source=gtgrthrst4577&utm_medium=ap-books&utm_content=recommend&utm_campaign=ap-202104)

🌟全文可以至下方連結觀看或是補充
https://hackmd.io/@LHB-0222/RegEx

全文分享至

https://www.facebook.com/LHB0222/

https://www.instagram.com/ahb0222/

有疑問想討論的都歡迎於下方留言

喜歡的幫我分享給所有的朋友 \o/

有所錯誤歡迎指教

# [:page_with_curl: 全部文章列表](https://hackmd.io/@LHB-0222/AllWritings)


![](https://i.imgur.com/47HlvGH.png)

