redballoon 发表于 2023-3-14 16:02

萌新自学正则表达式的学习笔记

本帖最后由 redballoon 于 2023-3-14 21:01 编辑

# 正则表达式

正则表达式测试工具网址:(https://tool.oschina.net/regex/)

正则表达式:**正则表达式**,又称规则表达式**。**(英语:Regular Expression,在代码中常简写为regex、regexp或RE),[计算机科学](https://baike.baidu.com/item/计算机科学/9132)的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

正则表达式是对[字符](https://baike.baidu.com/item/字符)串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

>实例引入

电子邮件组成格式:一段字符串 + @ 符号 + 某个域名

URL的组成格式:协议类型 + 冒号加双斜线 + 域名和路径

```python
+://[^\s]*
```

用这个正则表达式匹配一个字符串如果这个字符串中包含类似URL的文本就会被提取出来

>正则常用匹配规则





## Match 方法

向<span>match</span>传入要匹配的字符串,以及正则表达式就可以检测这个正则表达式是否匹配字符串      

<span>match</span>方法会尝试从字符串的<span>起始位置</span>匹配正则表达式

如果匹配------就会返回匹配成功的结果

如果不匹配------就返回<span>None</span>

>实例



**运行结果:**



```
^Hello\s\d\d\d\s\d{4}\s\w{10}
```

+ ^匹配字符串的开头,以Hello开头

+ \s匹配空白字符,用来匹配目标字符串的空格

+ \d匹配数字,3个\d的匹配123

+ 再一个\s匹配空格

+ 后面的4567,依然能用4个\d来匹配,但是这么写比较繁琐

所以后面可以跟{4}代表匹配前面的规则4次,也就是匹配4个数字

+ 后面再接一个空白符,最后\w{10}匹配10个字母及下划线

在match方法中第一个参数传入正则表达式 第二个参数传入要匹配的字符串

打印输出结果是SRE_Match对象,证明成功匹配

该对象有两个方法:

+ group方法可以输出匹配的内容

结果是Hello 123 4567 World_This

+ span方法可以输出匹配的范围

结果是 (0, 25)

>实例引入

从一段文本中提取出邮件或电话号码等内容可以使用()括号将想提取的子字符串括起来()括号实际上标记了一个子表达式的开始和结束位置被标记的每个子表达式会依次对应每一个分组

调用group方法传入分组的索引即可获取提取的结果

>实例



**运行结果:**



可以看到打印了1234567,这就是我们想要匹配的结果。

+ group(1)输出第一个被小括号包裹着的匹配结果,如果正则表达式后面还有小括号包括的内容,那么可以依次用group(2)、group(3)等等来获取结果。
+ group()输出完整的匹配结果。

出现空白字符就用\s匹配,出现数字就用\d匹配,我们发现这样做会很烦琐而且工作量非常大

可以用.*这个万能匹配来减少这些工作

. 可以匹配任意字符(除换行符)

*可以匹配前面的字符0次或无限次

> 代码改进



**运行结果:**



可以看到group匹配到了全部的字符串,span方法输出了匹配全部的范围(0,41)

有时候.*匹配到的并不是我们想要的,这时候怎么办呢?

看下一个例子

我们还是想获取中间的数字



**运行结果:**



我们发现只得到了 7 ,这是怎么回事呢?

#### 贪婪匹配和非贪婪匹配

在贪婪匹配下.* 会匹配尽可能多的字符正则表达式中 .* 后面是\d+,也就是至少一个数字,并没有指定具体多少个数字因此 .* 就尽可能匹配多的字符。这里就把123456匹配给了 \d+ 留下一个满足条件的数字7最后得到的内容就只有数字7了。

非贪婪匹配只需要在后面加 ? 即可。



**运行结果:**



这里只把 `.*` 改成 `.*?` 就能匹配到1234567了

贪婪匹配:尽可能匹配多的字符

非贪婪匹配:尽可能匹配少的字符

当`.*?`匹配到Hello后面的空白字符时,在往后的字符就是数字了,而 `\d+` 恰好可以匹配数字,那么`.*?`就不再匹配了,就交给后面 `\d+` 进行匹配后面的数字,这样的话 `.*?`就匹配了尽可能少的字符,`\d+`的结果就是1234567了。

在匹配时字符串中间尽量使用非贪婪匹配,也就是`.*?`来代替`.*`以免出现匹配结果缺失的情况

小细节[^注意]:需要注意的是如果匹配的结果出现在匹配结尾 .*? 就可能匹配不到任何内容了,因为它会匹配尽可能少的内容。

#### 修饰符re.S

```python
import re

content = 'http://weibo.com/comment/KEraCN'
result1 = re.match('http.*?comment/(.*?)', content)         #尽可能匹配少的内容
result2 = re.match('http.*?comment/(.*)', content)      # 尽可能匹配多的内容
print('result1',result1.group(1))
print('result2'.result2.group(1))

```

**运行结果:**

```python
result1                        
result2 KEraCN
```

正则表达式可以包含一些可选标志修饰符来控制匹配的模式<b>修饰符</b>被指定为一个可选的标志

```python
import re
content = '''Hello 1234567 World_This
is a Regex Demo'''
result = re.match('^He.*?(\d+).*?Demo$', content)
print(result.group(1))
```

**运行结果:**

```python
Traceback (most recent call last):
File "D:/PythonSpider/正则表达式/c1.py", line 27, in <module>
    print(result.group(1))
AttributeError: 'NoneType' object has no attribute 'group'

Process finished with exit code 1
```

为什么加个换行符就匹配不到了呢?

因为匹配的是除换行符之外的任意字符当遇到换行符时.*?就不能匹配了,导致匹配失败 报错

解决:修饰符 re.S

作用是匹配包括换行符在内的所有字符

```python
result = re.match('^He.*?(\d+).*?Demo$', content, re.S)
```

**运行结果:**

```python
1234567
```

## 其他修饰符:

| 修饰符 | 描述                                                         |
| ------ | ------------------------------------------------------------ |
| re.I   | 使匹配对大小写不敏感                                       |
| re.L   | 做本地化识别(locale-aware)匹配                           |
| re.M   | 多行匹配,影响 ^ 和 $                                        |
| re.S   | 使匹配包括换行符在内的所有字符                               |
| re.U   | 根据Unicode字符集解析字符。这个标志影响\w、\W、\b和\B      |
| re.X   | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解 |

如果目标字符串里面有包含`.`就需要用到<b>转义字符匹配</b>

> 代码示例



**运行结果:**


## Search方法

```python
import re
content = 'Extra strings Hello 1234567 World_This is a Regex Demo Extra strings'
result = re.match('Hello.*?(\d+).*?Demo', content)
print(result)
```

**运行结果:**

```python
None
```

看到运行结果是不是感到奇怪,这是什么鬼,其实,我们上面介绍match方法是有提到,match方法是从字符串的<span>起始位置</span>匹配的,而我们可以看到要匹配的起始位置并不是Hello,所以产生错误。

这种匹配方法需要考虑开头内容,这是很不方便的。它适合检测某个字符串是否符合某个正则表达式的规则。、

> 这就用到search方法

在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果,就是说,正则表达式可以是字符串的一部分。

匹配时,search方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容。

如果搜索完了还没有找到,就返回<span>None</span>

>修改一下上面代码

```
import re
content = 'Extra strings Hello 1234567 World_This is a Regex Demo Extra strings'
result = re.search('Hello.*?(\d+).*?Demo', content)
print(result)
```

**运行结果:**

```python
<re.Match object; span=(14, 54), match='Hello 1234567 World_This is a Regex Demo'>
```

## Findall方法

会搜索整个字符串,然后返回匹配正则表达式的所有内容。

正则 re.findall 的简单用法(返回string中所有与pattern相匹配的全部字串,返回形式为数组)
语法:

```python
findall(pattern, string, flags=0)
```

+ r 标识 :查找全部 r 标识代表后面是正则的语句

```python
import re
str1 = re.findall(r"zhihu","https://zhuanlan.zhihu.com/c_1137363974214598656")
print (str1)
```

**运行结果:**

```python
['zhihu']
```

+ 符号 ^ :表示匹配以https开头的的字符串返回

```python
import re
str2 = re.findall(r"^https","https://zhuanlan.zhihu.com/c_1137363974214598656")
print (str2)
```

**运行结果:**

```python
['https']
```

+ 符号 $ :表示以56结尾的字符串返回,判断是否字符串结束的字符串
+ 符号 [ ] :匹配括号中的其中一个字符

```python
import re
str4 = re.findall(r"o","https://zhuanlan.zhihu.com/c_1137363974214598656")
print (str4)
```

**运行结果:**

```python
['co']
```



## Sub方法

如果想要把一串文本中的所有数字都去掉,只用字符串的 replace 方法,太繁琐,这是可以用<b>sub方法</b>

```python
import re

content = '53akda37Yjda873isL7g'
content = re.sub('\d+','',content)
print(content)
```

**运行结果:**

```python
akdaYjdaisLg
```

只需要给第一个参数传入\d+ 来匹配所有的数字,第二个参数就是替换成的字符串,我想去掉所以赋值为空。

## Compile方法

这个方法可以将正则字符串编译成正则表达式对象,以便在后面的匹配中复用。



[^注意]: 需要注意的是如果匹配的结果出现在匹配结尾 .*? 就可能匹配不到任何内容了,因为它会匹配尽可能少的内容。

wei9999 发表于 2023-3-14 17:25

谢谢分享,

MakoStar 发表于 2023-3-14 17:29

我有个正则网站:https://regex101.com/ 里面还挺全面的还支持中文

alongzhenggang 发表于 2023-3-14 20:53

ie15 发表于 2023-3-14 17:08
不太会欣赏

哈哈哈哈~重在参与~
页: [1]
查看完整版本: 萌新自学正则表达式的学习笔记