python re 匹配多行_Python正则表达式,看这一篇就够了

06f6860e7a246d6c833826b9309ab0fa.gif9319e08a0b9e76e5a618bc662b84dacd.png

作者 | 猪哥

来源 | 裸睡的猪(ID: IT--Pig)

大多数编程语言的正则表达式设计都师从Perl,所以语法基本相似,不同的是每种语言都有自己的函数去支持正则,今天我们就来学习 Python中关于 正则表达式的函数。

5bcfa6a086270a9680098b6199e25ac8.png

re模块主要定义了9个常量、12个函数、1个异常,每个常量和函数猪哥都会通过实际代码案例讲解,让大家能更直观的了解其作用!

注:为避免出现代码格式错乱,猪哥尽量使用代码截图演示哦。

8783ac884abafd2c72a48f7770763457.png

re模块简介

聊到Python正则表达式的支持,首先肯定会想到re库,这是一个Python处理文本的标准库

标准库的意思表示这是一个Python内置模块,不需要额外下载,目前Python内置模块大概有300个。可以在这里查看Python所有的内置模块:https://docs.python.org/3/py-modindex.html#cap-r

因为re是内置模块,所以不需要再下载,使用时直接引入即可:

import re

re模块官方文档:https://docs.python.org/zh-cn/3.8/library/re.html

re模块库源码:https://github.com/python/cpython/blob/3.8/Lib/re.py

74e5a10b4285a4c348b0597bfb671a40.png

re模块常量

常量即表示不可更改的变量,一般用于做标记。

re模块中有9个常量,常量的值都是int类型!

d87777c4cb87c4ede16c1aa1c4e4c90b.png

上图我们可以看到,所有的常量都是在RegexFlag枚举类来实现,这是在Python 3.6做的改版。在Python 3.6以前版本是直接将常量写在re.py中,使用枚举的好处就是方便管理和使用!

c6dda17770d20ea41e4627e79a72734a.png

下面我们来快速学习这些常量的作用及如何使用他们,按常用度排序!

1. IGNORECASE

语法:re.IGNORECASE 或简写为 re.I

作用:进行忽略大小写匹配。

代码案例:

ba174cc94559bb80b40b42a6aa5ce411.png

在默认匹配模式下大写字母B无法匹配小写字母b,而在 忽略大小写 模式下是可以的。

2. ASCII

语法:re.ASCII 或简写为 re.A

作用:顾名思义,ASCII表示ASCII码的意思,让w,W,b,B,d,D,sS只匹配ASCII,而不是Unicode。

代码案例:

36ca211b7a8f3976da5d79a30ce5788a.png

在默认匹配模式下w+匹配到了所有字符串,而在ASCII模式下,只匹配到了a、b、c(ASCII编码支持的字符)。

注意:这只对字符串匹配模式有效,对字节匹配模式无效。

3. DOTALL

语法:re.DOTALL 或简写为 re.S

作用:DOT表示.,ALL表示所有,连起来就是.匹配所有,包括换行符默认模式下.是不能匹配行符的。

代码案例:

3064ecfc91d5ef98d9c8d6b2424264e3.png

在默认匹配模式下.并没有匹配换行符,而是将字符串分开匹配;而在re.DOTALL模式下,换行符与字符串一起被匹配到。

注意:默认匹配模式下.并不会匹配换行符

4. MULTILINE

语法:re.MULTILINE 或简写为 re.M

作用:多行模式,当某字符串中有换行符,默认模式下是不支持换行符特性的,比如:行开头 和 行结尾,而多行模式下是支持匹配行开头的。

代码案例:

63773ceb236d2a18afe58fe926ea04f4.png

正则表达式中^表示匹配行的开头,默认模式下它只能匹配字符串的开头;而在多行模式下,它还可以匹配 换行符后面的字符。

注意:正则语法中^匹配行开头、A匹配字符串开头,单行模式下它两效果一致,多行模式下A不能识别

5. VERBOSE

语法:re.VERBOSE 或简写为 re.X

作用:详细模式,可以在正则表达式中加注解!

代码案例:

899b16bde1bf932a15c4288e8e3fc80f.png

默认模式下并不能识别正则表达式中的注释,而详细模式是可以识别的。

当一个正则表达式十分复杂的时候,详细模式或许能为你提供另一种注释方式,但它不应该成为炫技的手段,建议谨慎考虑后使用!

6.LOCALE

语法:re.LOCALE 或简写为 re.L

作用:由当前语言区域决定w,W,b,B和大小写敏感匹配,这个标记只能对byte样式有效。这个标记官方已经不推荐使用,因为语言区域机制很不可靠,它一次只能处理一个 “习惯”,而且只对8位字节有效。

注意:由于这个标记官方已经不推荐使用,而且猪哥也没使用过,所以就不给出实际的案例!

7.UNICODE

语法:re.UNICODE 或简写为 re.U

作用:与 ASCII 模式类似,匹配unicode编码支持的字符,但是 Python 3 默认字符串已经是Unicode,所以有点冗余。

8. DEBUG

语法:re.DEBUG

作用:显示编译时的debug信息。

代码案例:

784371eac1a2077c652c428b53b716be.png

虽然debug模式下确实会打印编译信息,但猪哥并不理解这是什么语言 以及表达的含义,希望了解的朋友能不吝赐教。

9.TEMPLATE

语法:re.TEMPLATE 或简写为 re.T

作用:猪哥也没搞懂TEMPLATE的具体用处,源码注释中写着:disable backtracking(禁用回溯),有了解的同学可以留言告知!

cf83d314566c0371e7614d6e06cd99ab.png

10. 常量总结

9个常量中,前5个(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用处,两个(LOCALE、UNICODE)官方不建议使用、两个(TEMPLATE、DEBUG)试验性功能,不能依赖。

常量在re常用函数中都可以使用,查看源码可得知。

04f8cc460f1fe874796660827cc2a1ea.png

常量可叠加使用,因为常量值都是2的幂次方值,所以是可以叠加使用的,叠加时请使用 |符号,请勿使用+符号!

18193df92e7338f47d02354b9fb21965.png

最后来一张思维导图总结一下re模块中的常量吧,需要高清图或者xmind文件的同学可在文章末尾获取。

34db4f3ec907f6064f79a34854e7f81d.pngc510cb34d3e01de1357cd531137d8ec1.png

re模块函数

re模块有12个函数,猪哥将以功能分类来讲解;这样更具有比较性,同时也方便记忆。

1.查找一个匹配项

查找并返回一个匹配项的函数有3个:search、match、fullmatch,他们的区别分别是:

  1. search: 查找任意位置的匹配项

  2. match: 必须从字符串开头匹配

  3. fullmatch: 整个字符串与正则完全匹配

我们再来根据实际的代码案例比较:

案例1:

763f73cd3974419653b4dacee85acd86.png

案例1中search函数是在字符串中任意位置匹配,只要有符合正则表达式的字符串就匹配成功,其实有两个匹配项,但search函数值返回一个。

match函数是要从头开始匹配,而字符串开头多了个字母a,所以无法匹配,fullmatch函数需要完全相同,故也不匹配!

案例2:

31bb2d0389ec3ad98127919ba4989830.png

案例2删除了text最开头的字母a,这样match函数就可以匹配啦,而fullmatch函数依然不能完全匹配!

案例3:

4e194056113bc3e90198362c27e2d62d.png

案例3中,我们只留下一段文字,并且与正则表达式一致;这时fullmatch函数终于可以匹配了。

完整案例:

a8be8c3f0d7026bc46611bb764d54d17.png

注意:查找 一个匹配项 返回的都是一个匹配对象(Match)。

2.查找多个匹配项

讲完查找一项,现在来看看查找多项吧,查找多项函数主要有:findall函数finditer函数

  1. findall: 从字符串任意位置查找,返回一个列表
  2. finditer:从字符串任意位置查找,返回一个迭代器

两个方法基本类似,只不过一个是返回列表,一个是返回迭代器。我们知道列表是一次性生成在内存中,而迭代器是需要使用时一点一点生成出来的,内存使用更优。

c8751105caf6c887f3ae8bcaa2bf2f83.png

如果可能存在大量的匹配项的话,建议使用finditer函数,一般情况使用findall函数基本没啥影响。

3.分割

re.split(pattern, string, maxsplit=0, flags=0)函数:用pattern分开 string ,maxsplit表示最多进行分割次数,flags表示模式,就是上面我们讲解的常量!

7a9023f85e3fe3adb59b1e1a0fba4c35.png

注意:str模块也有一个 split函数 ,那这两个函数该怎么选呢?str.split函数功能简单,不支持正则分割,而re.split支持正则。

关于二者的速度如何? 猪哥实际测试了一下,在相同数据量的情况下使用re.split函数与str.split函数执行次数执行时间对比图:

ef19b7a1703b72fe33a9694224e02f41.png

通过上图对比发现,1000次循环以内str.split函数更快,而循环次数1000次以上后re.split函数明显更快,而且次数越多差距越大!

所以结论是:在 不需要正则支持 且 数据量和数次不多 的情况下使用str.split函数更合适,反之则使用re.split函数

注:具体执行时间与测试数据有关!

4.替换

替换主要有sub函数subn函数,他们功能类似!

先来看看sub函数的用法:

re.sub(pattern, repl, string, count=0, flags=0)函数参数讲解:repl替换掉string中被pattern匹配的字符, count表示最大替换次数,flags表示正则表达式的常量。

值得注意的是:sub函数中的入参:repl替换内容既可以是字符串,也可以是一个函数哦!如果repl为函数时,只能有一个入参:Match匹配对象。

92c8032f576621eb8e9c530154c03e3d.png

re.subn(pattern, repl, string, count=0, flags=0)函数与re.sub函数功能一致,只不过返回一个元组 (字符串, 替换次数)。

80b2d6d17cfe4a52af71748e4239f7aa.png

5.编译正则对象

compile函数 与 template函数将正则表达式的样式编译为一个 正则表达式对象 (正则对象Pattern),这个对象与re模块有同样的正则函数(后面我们会讲解Pattern正则对象)。

47c927b93d45331f3a9722e637355d6d.png

template函数compile函数类似,只不过是增加了我们之前说的re.TEMPLATE模式,我们可以看看源码。

1920446ecc3963fe9699b0a443241c81.png

6.其他

re.escape(pattern) 可以转义正则表达式中具有特殊含义的字符,比如:.或者*,举个实际的案例:

b8ff331d649f7ce105da02afd84d3cfe.png

re.escape(pattern)看似非常好用省去了我们自己加转义,但是使用它很容易出现转义错误的问题,所以并不建议使用它转义,而建议大家自己手动转义!

re.purge 函数作用就是清除 正则表达式缓存,具体有什么缓存呢?我们来看看源码就知道它背地里干了 什么:

ce2c920dbb05b157ef2682cfdfaf8801.png

看方法大概是清除缓存吧,我们再来看看具体的案例:

8b478789cb212267c8ed3ca48797eb0c.png

猪哥在两个案例之间使用了re.purge函数清除缓存,然后分别比较前后案例源码里面的缓存,看看是否有变化!

43b25f500ca0807f59c68ad8e09bc581.png

7.总结

同样,最后来一张思维导图总结一下re模块中的函数吧,需要高清图或者xmind文件的同学可在末尾获取。

43c5fbb1a14a6d0e6c995a11c7de49e0.png6a98bd3b3ca20541be652385119cea1f.png

re模块异常

re模块还包含了一个正则表达式的编译错误,当我们给出的正则表达式是一个无效的表达式(就是表达式本身有问题)时,就会raise一个异常!

我们来看看具体的案例吧:

124c9b214375604372b4d8cf706b88c9.png

上图案例中我们可以看到,在编写正则表达式中我们多写了一个后括号,这导致执行结果报错;而且是在其他所有案例执行之前,所以说明是在正则表达式编译时期就报错了。

注意:这个异常一定是 正则表达式 本身是无效的,与要匹配的字符串无关!

9710abbd50d9bde04dffcf06e835a42f.png

正则对象Pattern

关于re模块的常量、函数、异常我们都讲解完毕,但是完全有必要再讲讲正则对象Pattern

1. 与re模块 函数一致

re模块的函数中有一个重要的函数compile函数,这个函数可以预编译返回一个正则对象,此正则对象拥有与re模块相同的函数,我们来看看Pattern类的源码。

7edadee9264400e3e77ae9d192ab8bd5.png

既然是一致的,那到底该用re模块还是正则对象Pattern

而且,有些同学可能看过re模块的源码,你会发现其实compile函数与 其他re函数(search、split、sub等等) 内部调用的是同一个函数,最终还是调用正则对象的函数!

7d94c3129a8589c205cbdefedc35d0b7.png

也就是说下面 两种代码写法底层实现 其实是一致的:

# re函数re.search(pattern, text)# 正则对象函数compile = re.compile(pattern)compile.search(text)

那还有必要使用compile函数得到正则对象再去调用search函数吗?直接调用re.search 是不是就可以?

2. 官方文档怎么说

关于到底该用re模块还是正则对象Pattern,官方文档是否有说明呢?

3897277ac5239f02a8f3b8d0b179a064.png

官方文档推荐:在多次使用某个正则表达式时推荐使用正则对象Pattern以增加复用性,因为通过re.compile(pattern)编译后的模块级函数会被缓存!

3. 实际测试又如何?

上面官方文档推荐我们在 多次使用某个正则表达式时使用正则对象,那实际情况真的是这样的吗?

我们再实测一下吧

327d2e77807160a979fc810ad61fb88d.png

猪哥编写了两个函数,一个使用re.search函数另一个使用compile.search函数,分别(不同时)循环执行count次(count从1-1万),比较两者的耗时!

得出的结果猪哥绘制成折线图:

d64a915ab44964668e7452b0f3d91d4e.png

得出的结论是:100次循环以内两者的速度基本一致,当超出100次后,使用 正则对象Pattern的函数 耗时明显更短,所以比re模块要快!

通过实际测试得知:Python 官方文档推荐 多次使用某个正则表达式时使用正则对象函数 基本属实!

3bfebb6c94ed6b138402482b5afc66f9.png

注意事项

Python 正则表达式知识基本讲解完毕,最后稍微给大家提一提需要注意的点。

1.字节串 与 字符串

模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字节串 (bytes)。但是,Unicode 字符串与8位字节串不能混用!

2.r 的作用

正则表达式使用反斜杠(’’)来表示特殊形式,或者把特殊字符转义成普通字符。

而反斜杠在普通的 Python 字符串里也有相同的作用,所以就产生了冲突。

解决办法是对于正则表达式样式使用 Python 的原始字符串表示法;在带有 ‘r’ 前缀的字符串字面值中,反斜杠不必做任何特殊处理。

3.正则查找函数 返回匹配对象

查找一个匹配项(search、match、fullmatch)的函数返回值都是一个 匹配对象Match,需要通过match.group获取匹配值,这个很容易忘记。

e04b4f9035e16c24093bc19e3417d953.png

另外还需要注意:match.group 与match.groups 函数的差别!

4.重复使用某个正则

如果要重复使用某个正则表达式,推荐先使用 re.compile(pattern)函数返回一个正则对象,然后复用这个正则对象,这样会更快!

5.Python 正则面试

笔试可能会遇到需要使用Python正则表达式,不过不会太难的,大家只要记住那几个方法的区别,会正确使用,基本问题不大。

文章所有内容精华猪哥已经整理成一份思维导图:链接(或阅读原文):https://pan.baidu.com/s/10MMpuf6Rcba-gvBo1oIzlw 密码:y6z3

80fdaf3ff0e308e54f7c2bb6123ef69d.png07faa96eb197e06f76103c3e3ba8f19a.png

今日福利

遇见陆奇

同样作为“百万人学 AI”的重要组成部分,2020 AIProCon 开发者万人大会将于 7 月 3 日至 4 日通过线上直播形式,让开发者们一站式学习了解当下 AI 的前沿技术研究、核心技术与应用以及企业案例的实践经验,同时还可以在线参加精彩多样的开发者沙龙与编程项目。参与前瞻系列活动、在线直播互动,不仅可以与上万名开发者们一起交流,还有机会赢取直播专属好礼,与技术大咖连麦。

  • 你点的每个“在看”,我都认真当成了AI

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/472643.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nsga2算法_用遗传算法进行容量管理 让虚拟机放置策略更优

随着互联网技术的高速发展,云计算已经成为各行各业的“水电煤”,成为“互联网”的基础设施,而数据中心则是云服务背后的刚性保障。无论是传统的数据中心,还是云形态的数据中心,虚拟化技术都是提升其资源利用率、降低管…

php预处理_如何用预处理让 PHP 更先进

原标题:如何用预处理让 PHP 更先进先来点趣事。不久以前, 来添加 Python 的 range 语法。然后, 大虾 ,并且 建议为 PHP 添加 C# 风格的 getter 和 setter。我意识到对于一个局外人来说,建议和实现新的语言特性是件缓慢…

天池 在线编程 两句话中的不常见单词(哈希计数)

文章目录1. 题目2. 解题1. 题目 给定两个句子 A 和 B 。 (句子是一串由空格分隔的单词。每个单词仅由小写字母组成。) 如果一个单词在其中一个句子中只出现一次,在另一个句子中却没有出现,那么这个单词就是不常见的。 返回所有…

iphone屏幕上的圆圈怎么设置_iPhone手机屏幕突然变暗或者黑屏怎么办?看这里你就知道该怎么办...

阅读本文前,请您先点击上面的蓝色字体,再点击“关注”,这样您就可以继续免费收到各种有关娱乐的文章了。每天都有分享,完全是免费订阅,请放心关注。 …

C语言库函数大全及应用实例六

C语言库函数大全及应用实例六 原文:C语言库函数大全及应用实例六[编程资料]C语言库函数大全及应用实例六函数名: getlinesettings 功 能: 取当前线型、模式和宽度 用 法: void far getlinesettings(struct linesettingstype far *lininfo): 程序例: <?xml:namespace prefix…

天池 在线编程 最小的行程(动态规划)

文章目录1. 题目2. 解题1. 题目 给定一个二维矩阵&#xff0c;找到从上到下的最小路径。只能向左下&#xff0c;下&#xff0c;右下移动 所有的元素都是正整数 矩阵大小 < 200x200 样例 1: 输入: 1 2 3 4 5 6 7 8 9 输出: 12 解释: 最短的路径为:1->4->7, 返回12.样…

fluent瞬态计算终止条件在哪里设置_Fluent案例7【圆柱绕流】

一个瞬态的圆柱绕流案例知识点&#xff1a;瞬态圆柱绕流的模拟一个后处理的方法&#xff1a;将瞬态模型中一个点的速度变化绘成图表并将数值导出excel文件模型如下图所示&#xff0c;左边界为速度边界进口速度0.5m/s&#xff0c;试模拟出计算域中的速度变化打开workbench&#…

qq登录界面句柄_别小看QQ邮箱测试,80%的测试新手都不能写出完整的测试用例~...

对于很多刚进入测试行业的新手来说&#xff0c;由于自身的工作经验不足&#xff0c;虽有测试基础知识傍身&#xff0c;但仍然很难将测试用例写的尽善尽美。因此&#xff0c;学习别人的测试经验&#xff0c;将是你成为测试达人的必经之路。今天&#xff0c;我们就以QQ邮箱为例&a…

LeetCode 878. 第 N 个神奇数字(二分查找)

文章目录1. 题目2. 解题1. 题目 如果正整数可以被 A 或 B 整除&#xff0c;那么它是神奇的。 返回第 N 个神奇数字。由于答案可能非常大&#xff0c;返回它模 10^9 7 的结果。 示例 1&#xff1a; 输入&#xff1a;N 1, A 2, B 3 输出&#xff1a;2示例 2&#xff1a; 输…

为什么百度统计里面的广告那么多_里面东西一模一样的桶装方便面为什么比袋装贵那么多?...

今天特地买了一桶桶装的和一袋袋装的&#xff0c;同品牌同系列同口味&#xff0c;里面面饼&#xff0c;配料包也一模一样&#xff0c;桶装的只是多了一个小勺子&#xff0c;为什么一袋二元五&#xff0c;一桶就要卖4元&#xff1f;并且大家好像都不觉得有什么不妥……(好吧我就…

LeetCode 1790. 仅执行一次字符串交换能否使两个字符串相等

文章目录1. 题目2. 解题1. 题目 给你长度相等的两个字符串 s1 和 s2 。 一次 字符串交换 操作的步骤如下&#xff1a;选出某个字符串中的两个下标&#xff08;不必不同&#xff09;&#xff0c;并交换这两个下标所对应的字符。 如果对 其中一个字符串 执行 最多一次字符串交换…

gradle 上传jar包_Gradle学习记录014 关于依赖的声明

详细学习Gradle构建的依赖声明。该学习记录基于Gradle官方网站资料。本篇参考链接如下&#xff1a;https://docs.gradle.org/current/userguide/declaring_dependencies.html声明一个模块作为依赖通常声明一个模块作为依赖&#xff0c;需要指定这个模块的版本。Gradle提供了一套…

win10版本查看_想知道电脑中安装的win10版本号,用这3招就对了,一键查看

自从微软在Windows 10中更改了发布模型后&#xff0c;很多用户就对找出他们在电脑上安装的Windows 10版本感兴趣。大家可能都已经知道&#xff0c;微软不会再发布Windows的主要版本&#xff0c;而是会不断发布更新&#xff0c;这让人想起许多Linux发行版的滚动发行模型。如果你…

LeetCode 1791. 找出星型图的中心节点(图出入度)

文章目录1. 题目2. 解题1. 题目 有一个无向的 星型 图&#xff0c;由 n 个编号从 1 到 n 的节点组成。 星型图有一个 中心 节点&#xff0c;并且恰有 n - 1 条边将中心节点与其他每个节点连接起来。 给你一个二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi] 表示在节…

ole db 错误 通讯链接失败_西门子PLC1200的S7通讯(同一项目下)--GET接收指令

西门子PLC1200的S7通讯&#xff08;同一项目下&#xff09;--GET接收指令1.0 首先在同一项目下&#xff0c;组态两个PL&#xff0c;如下图&#xff0c;组态了2个1200PLC 1214C的PLC2.0 点击链接里面&#xff0c;在窗口的右上角选择S7连接&#xff0c;这个窗口可以看到本地ID&am…

电磁波

可见光谱只占有宽广的电磁波谱的一小部分。电磁波&#xff0c;又称电磁辐射&#xff0c;是由同相振荡且互相垂直的电场与磁场在空间中以波的形式传递能量和动量&#xff0c;其传播方向垂直于电场与磁场构成的平面。电磁辐射的载体为光子&#xff0c;不需要依靠介质传播&#xf…

LeetCode 1792. 最大平均通过率(优先队列)

文章目录1. 题目2. 解题1. 题目 一所学校里有一些班级&#xff0c;每个班级里有一些学生&#xff0c;现在每个班都会进行一场期末考试。 给你一个二维数组 classes &#xff0c;其中 classes[i] [passi, totali] &#xff0c;表示你提前知道了第 i 个班级总共有 totali 个学生…

分段线性插值c语言程序_【短道速滑】OpenCV中cvResize函数使用双线性插值缩小图像长宽大小一半时速度飞快(比最近邻还快)之异象解析和自我实现。...

点击上方↑↑↑“OpenCV学堂”关注我作者网名&#xff1a;laviewpbt是图像处理&#xff0c;算法实现与加速优化方面的大神&#xff01;其开发的imageshop软件大小只有1MB&#xff0c;却实现了非常丰富与复杂的各种图像处理功能&#xff0c;邮箱地址为&#xff1a;Email: laview…

端口可以随便设置吗_驱动可以随便更新吗?

答案是&#xff0c;真的不可以&#xff0c;我真的吐了&#xff0c;当你用驱动感觉合适&#xff0c;显卡驱动没有卡屏或者黑屏什么的&#xff0c;网卡用着正常的话就不要盲目更新了&#xff0c;我今天就是更新了网卡&#xff0c;结果就断网了&#xff0c;删除了恢复旧版没用&…

IOS学习:常用第三方库(GDataXMLNode:xml解析库)

IOS学习&#xff1a;常用第三方库&#xff08;GDataXMLNode&#xff1a;xml解析库&#xff09; 解析 XML 通常有两种方式&#xff0c;DOM 和 SAX&#xff1a; DOM解析XML时&#xff0c;读入整个XML文档并构建一个驻留内存的树结构&#xff08;节点树&#xff09;&#xff0c;通…