正则表达式

# 正则表达式

我们到网站上爬取数据,需要知道什么样的数据是我们想要爬取的,什么样的数据是网页上不会变化的。

正则表达式通常被用来`检索、替换`那些符合某个`模式(规则)`的`文本`。

### 模式介绍

|模式|描述|
-------|--------|
|^|匹配字符串的开头|
|$|匹配字符串的末尾。|
|.|匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。|
|[...]|用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'|
|[^...]|不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。|
|re*|匹配0个或多个的表达式。|
|re+|匹配1个或多个的表达式。|
|re?|匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式|
|re{ n}|精确匹配 n 个前面表达式。例如, o{2} 不能匹配 "Bob" 中的 "o",但是能匹配 "food" 中的两个 o。|
|re{ n,}|匹配 n 个前面表达式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。"o{1,}" 等价于 "o+"。"o{0,}" 则等价于 "o*"。|
|re{ n, m}|匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式|
|a\| b|匹配a或b|
|(re)|匹配括号内的表达式,也表示一个组|
|(?imx)|正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。|
|(?-imx)|正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。|
|(?: re)|类似 (...), 但是不表示一个组|
|(?imx: re)|在括号中使用i, m, 或 x 可选标志|
|(?-imx: re)|在括号中不使用i, m, 或 x 可选标志|
|(?#...)|注释.|
|(?= re)|前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。|
|(?! re)|前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功|
|(?> re)|匹配的独立模式,省去回溯。|
|\w|匹配字母数字及下划线|
|\W|匹配非字母数字及下划线|
|\s|匹配任意空白字符,等价于 [\t\n\r\f].|
|\S|匹配任意非空字符|
|\d|匹配任意数字,等价于 [0-9].|
|\D|匹配任意非数字|
|\A|匹配字符串开始|
|\Z|匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。|
|\z|匹配字符串结束|
|\G|匹配最后匹配完成的位置。|
|\b|匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。|
|\B|匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。|
|\n, \t, 等.|匹配一个换行符。匹配一个制表符。等|
|\1...\9|匹配第n个分组的内容。|
|\10|匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。|


## 正则表达式最常见的字符

1)特殊字符:就是一些有特殊含义的字符。 $ () * + . [ ? \ ^ { |

2)限定符:用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。* + ? {n} {n,} {n,m}

3)定位符:用来描述字符串或单词的边界。^ $

4)其他字符:\w \W \s \S \d

我先不介绍这些字符有什么含义,我们直接进入python示例

### 基本用法

```
import re
re.match
re.search
re.compile
```

1)^ 匹配输入字符串开始的位置。

2). 匹配除换行符 \n 之外的任何单字符。

3)* 匹配前面的子表达式零次或多次。

4)$ 匹配输入字符串的结尾位置。    

```python
line = "huang123"

1. 以 h 开头
2. 以h开头后面跟着一个字符
3. 以h开头后面跟着任意数量的数字
4. 以3结尾
5. 以h开头,以3结尾,中间只有一个字符串
6. 以h开头,以3结尾,中间可以存在任意数量的字符串

# -*- coding: utf-8 -*-
import re

line = "huang123"

# 1. 测试以h开头
if re.match("^h", line):
    print("1. 以 h 开头")
    
# 1.1 search 测试
if re.search("^h", line):
     print("1.1 以 h 开头")
     
pattern = re.compile("^h")
if pattern.search(line):
     print('compile 测试')

# 2. 测试以h开头后面跟着一个字符
if re.match("^h.", line):
    print('2. 以h开头后面跟着一个字符')

# 3. 以h开头后面跟着任意数量的字符
if re.match("^h.*", line):
    print('3. 以h开头后面跟着任意数量的数字')

# 4. 以3结尾
if re.match(".*3$", line):
    print('4. 以3结尾')

# 5. 以h开头,以3结尾,中间只有一个字符串
if re.match("^h.3^", line):
    print("5. 以h开头,以3结尾,中间只有一个字符串")

# 6. 以h开头,以3结尾,中间可以存在任意数量的字符串
if re.match("^h.*3$", line):
    print("6. 以h开头,以3结尾,中间可以存在任意数量的字符串")
```


1)()标记一个子表达式的开始和结束位置。

2)?匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。

```
import re

line = 'ahuuhhaaahang123'
# 1. 想要获取huuh
# 2. 使用非贪婪限定符


# 想要获取huuh
regex_str = '.*(h.*h).*'

match_obj = re.match(regex_str, line)
if match_obj:
    print('非贪婪模式')
    print(match_obj.group(1))

# 2. 使用非贪婪限定符
regex_str = '.*?(h.*h).*'
match_obj = re.match(regex_str, line)
if match_obj:
    print('贪婪模式')
    print(match_obj.group(1))

regex_str = '.*?(h.*?h).*'
match_obj = re.match(regex_str, line)
if match_obj:
    print('双贪婪模式')
    print(match_obj.group(1))

1)+匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。

2){n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。

3){n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
4){n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。


import re

line = 'ahuuhhaaahhhhang123'

# 需要获取h和h之间,需要包含特定数量字符的子串
# 使用 + h和h之间至少要有一个字符
regex_str = '.*(h.+h).*'

match_obj = re.match(regex_str, line)
if match_obj:
    print('使用 + h和h之间至少要有一个字符')
    print(match_obj.group(0))
    print(match_obj.group(1))

# 使用*,h和h之间,只要有一个字符。
regex_str = '.*(h.{1}h).*'

match_obj = re.match(regex_str, line)
if match_obj:
    print('使用*,h和h之间,至少要有一个字符。')
    print(match_obj.group(1))

# 使用{2,},h 和 h 之间,至少要有两个字符。
regex_str = '.*(h,{2,}h).*'
match_obj = re.match(regex_str, line)
if match_obj:
    print('使用{2,},h 和 h 之间,至少要有两个字符。')
    print(match_obj.group(1))

#使用 {3,5} ,将h和h之间的字符数量限定在3-5个。
regex_str = '.*(h.{3,5}h).*'
match_obj = re.match(regex_str, line)
if match_obj:
    print('使用 {3,5} ,将h和h之间的字符数量限定在3-5个.')
    print(match_obj.group(1))
```

1)|指明两项之间的一个选择。

2)[123] 只要是123中的其中一个即可。

3)[0-9] 只要是0-9中的任意数字即可。

4)[^1] 非,只要不是1即可。


```
import re

line = 'sss127'

# 匹配sss127 或者 aaa
regex_string = '(sss127|aaa)'
match_obj = re.match(regex_string, line)
if match_obj:
    print('匹配到了:')
    print(match_obj.group(0))
    print(match_obj.group(1))


match_obj = re.match(regex_string, 'aaa')
if match_obj:
    print('匹配到了:')
    print(match_obj.group(0))
    print(match_obj.group(1))

# 匹配正确的手机号

regex_string = '1[345678][0-9]{9}'
match_obj = re.match(regex_string, '13722290987')
if match_obj:
    print('手机号正确')

```

1)\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。

2)\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。

3)\w 等价于[A-Za-z0-9_]。

4)\W 与\w相反。

5)\d 所有数字,等价于[0-9]。

```
impor
```


小练习

```
r"^[a2-9tjqk]{5}$"

akt5q
akt5e
akt
727ak
```

```
r'.*(.).*\1'

717ak
718ak
aa
aefakl
```

### search() vs. match()

```
c
abcdef

re.match('X', 'A\nB\nX', re.MULTILINE)
re.search('^X', 'A\nB\nX', re.MULTILINE)
```

## 练习

### 找到所有的副词(ly)

```
text = "He was carefully disguised but captured quickly by police."
re.findall(r"\w+ly", text)
```

### 重复字母的单词

```
re.match(r"\W(.)\1\W", " ff ")
```


### 做一个通讯录,list 和 dict 

```
text = """Ross McFluff: 834.345.1254 155 Elm Street

Ronald Heathmore: 892.345.3428 436 Finley Avenue
Frank Burger: 925.541.7625 662 South Dogwood Way


Heather Albrecht: 548.326.4584 919 Park Place"""

```

```
1、匹配一行文字中的所有开头的字母内容

# -*- coding=utf-8 -*-

import re

s="i love you not because of who you are, but because of who i am when i am with you"


pattern = '(\w)\w*'
res_list = re.findall(pattern,s)
print(res_list)


```

```
2、匹配一行文字中的所有开头的数字内容

import re

s="i love you not because 12sd 34er 56df e4 54434"

pattern = '\s[0-9]{1}'
res_list = re.findall(pattern,s)
print(res_list)

匹配一行文字中的所有开头的所有数字内容
import re

s="i love you not because 12sd 34er 56df e4 54434"

pattern = '\s[0-9]+'
res_list = re.findall(pattern,s)
print(res_list)

```
```
3、将第一个数字匹配出并返回

如:a1234b111, 返回 1234
如:bb1kk23445, 返回 1

要求写成函数,返回值是匹配好的数字。并一定做好测试
```

```
import re
m0 =  "在一九四九年新中国成立"
m1 =  "比一九九零年低百分之五点二"
m2 =  '人一九九六年击败俄军,取得实质独立'

translate_dict = {
    '零' : '0',
    '一' : '1',
    '二' : '2',
    '三' : '3',
    '四' : '4',
    '五' : '5',
    '六' : '6',
    '七' : '7',
    '八' : '8',
    '九' : '9',
}


def translate_year(message):
    a = re.findall("[零|一|二|三|四|五|六|七|八|九]+年", message)

    new_year = ''
    yeah = a[0]
    for letter in yeah:
        if letter in translate_dict:
            new_year += translate_dict[letter]
        else:
            new_year += letter

    print(new_year)

if __name__ == '__main__':
    translate_year(m1)
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值