目录
正则表达式是对字符串提取的一套规则,我们把这个规则用正则里面的特定语法表达出来,去匹配满足这个规则的字符串。正则表达式具有通用型,不仅python里面可以用,其他的语言也一样适用。
python中re模块提供了正则表达式的功能,常用的有四个方法(match、search、findall)都可以用于匹配字符串
match
匹配字符串
re.match()必须从字符串开头匹配!match方法尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。主要参数如下:
re.match(pattern, string)
# pattern 匹配的正则表达式
# string 要匹配的字符串
例子
import re
a = re.match('test','testasdtest')
print(a) #返回一个匹配对象
print(a.group()) #返回test,获取不到则报错
print(a.span()) #返回匹配结果的位置,左闭右开区间
print(re.match('test','atestasdtest')) #返回None

从例子中我们可以看出,re.match()方法返回一个匹配的对象,而不是匹配的内容。如果需要返回内容则需要调用group()。通过调用span()可以获得匹配结果的位置。而如果从起始位置开始没有匹配成功,即便其他部分包含需要匹配的内容,re.match()也会返回None。
单字符匹配
以下字符,都匹配单个字符数据。且开头(从字符串0位置开始)没匹配到,即使字符串其他部分包含需要匹配的内容,.match也会返回none

. 匹配任意一个字符
用几个句号表示几个字符
[En]
Use a few periods to represent a few characters
import re
a = re.match('..','testasdtest')
print(a.group()) #输出te
b = re.match('ab.','testasdtest')
print(b) #返回none,因为表达式是以固定的ab开头然后跟上通配符. 所以必须要先匹配上ab才会往后进行匹配

\d 匹配数字
一个\d代表一个数字。开头没匹配到,即使字符串其他部分包含需要匹配的内容,.match也会返回none
import re
a = re.match('\d\d','23es12testasdtest')
print(a)
b = re.match('\d\d\d','23es12testasdtest')
print(b) #要求匹配三个数字,匹配不到返回none
c = re.match('\d','es12testasdtest')
print(c) #起始位置没有匹配成功,一样返回none

\D 匹配非数字
开头没匹配到,即使字符串其他部分包含需要匹配的内容,.match也会返回none
import re
a = re.match('\D','23es12testasdtest')
print(a) #开头为数字所以返回none
b = re.match('\D\D','*es12testasdtest')
print(b) #返回*e
\s 匹配特殊字符,如空白,空格,tab等
import re
print(re.match('\s',' 23es 12testasdtest')) #匹配空格
print(re.match('\s',' 23es 12testasdtest')) #匹配tab
print(re.match('\s','\r23es 12testasdtest')) #匹配\r换行
print(re.match('\s','23es 12testasdtest')) #返回none

\S 匹配非空白
import re
print(re.match('\S',' 23es 12testasdtest')) #返回none
print(re.match('\S','\r23es 12testasdtest')) #none
print(re.match('\S','23es 12testasdtest'))

\w 匹配单词、字符,如大小写字母,数字,_ 下划线
import re
print(re.match('\w','23es 12testasdtest')) #返回none
print(re.match('\w\w\w','aA_3es 12testasdtest')) #返回none
print(re.match('\w\w\w','\n12testasdtest')) #返回none

\W 匹配非单词字符
import re
print(re.match('\W','23es 12testasdtest')) #返回none
print(re.match('\W',' 23es 12testasdtest')) #匹配空格

[ ] 匹配[ ]中列举的字符
只允许出现[ ]中列举的字符
import re
print(re.match('12[234]','232s12testasdtest')) #因为开头的12没匹配上,所以直接返回none
print(re.match('12[234]','1232s12testasdtest')) #返回123

[^2345] 不匹配2345中的任意一个
import re
print(re.match('12[^234]','232s12testasdtest')) #因为开头的12没匹配上,所以直接返回none
print(re.match('12[^234]','1232s12testasdtest')) #返回none
print(re.match('12[^234]','1252s12testasdtest')) #返回125
[a-z3-5] 匹配a-z或者3-5中的字符
import re
print(re.match('12[1-3a-c]','1232b12testasdtest')) #123
print(re.match('12[1-3a-c]','12b2b12testasdtest')) #12b
print(re.match('12[1-3a-c]','12s2b12testasdtest')) #返回none
表示数量
和上面写的一样,它们都匹配一个字符,所以如果我们想匹配多个字符,我们只能重复匹配。这显然是客观的,所以我们还需要学会表达字数。
[En]
Like those written above, they all match a single character, so if we want to match multiple characters, we can only repeat the match. This is obviously impersonal, so we also need to learn to express the number of characters.

* 出现0次或无数次
import re
a = re.match('..','testasdtest')
print(a.group()) #输出te
a = re.match('.*','testasdtest')
print(a.group()) #全部输出

import re
print(re.match('a*','aatestasdtest')) #匹配跟随在字母a后面的所有a字符
print(re.match('\d*','23aatestasdtest')) #匹配前面为数字的字符
print(re.match('a\d*','ad23aatestasdtest')) #输出a, 因为*也可以代表0次

+ 至少出现一次
import re
print(re.match('a+','aaatestasdtest')) #匹配前面为字母a的字符,且a至少有1一个
print(re.match('a+','atestasdtest')) #a
print(re.match('a+','caaatestasdtest')) #none

? 1次或则0次
import re
print(re.match('a?','abatestasdtest')) #匹配a出现0次或者1次数
print(re.match('a?','batestasdtest')) #输出空,因为a可以为0次
print(re.match('a?','aaatestasdtest')) #a出现0次或者1次,输出1个a

{m}指定出现m次
import re
print(re.match('to{3}','toooooabatestasdtest')) #匹配t以及跟随在后面的三个ooo
print(re.match('to{3}','tooabatestasdtest')) #只有两个0,返回none

{m,} 至少出现m次
import re
print(re.match('to{3,}','toooooabatestasdtest')) #匹配t以及跟随在后面的三个ooo至少出现3次
print(re.match('to{3,}','tooabatestasdtest')) #只有两个0,返回none

{m,n} 指定从m-n次的范围
import re
print(re.match('to{3,4}','toooabatestasdtest')) #刚好有三个ooo,成功匹配
print(re.match('to{3,4}','tooabatestasdtest')) #只有两个o,返回none
print(re.match('to{3,4}','toooooabatestasdtest')) #提取最多四个o

匹配边界

$ 匹配结尾字符
定义整个字符串必须以指定的字符串结尾
[En]
Defines that the entire string must end with the specified string
import re
print(re.match('.*d$','2testaabcd')) #字符串必须以d结尾
print(re.match('.*c','2testaabcd')) #字符串不是以c结尾,返回none

^ 匹配开头字符
定义整个字符串必须以指定字符开头
[En]
Defines that the entire string must begin with a specified character
import re
print(re.match('^2','2stoooabatestas')) #规定必须以2开头,否则none
print(re.match('^2s','2stoooabatestas')) #必须以2s开头
\b 匹配一个单词的边界
\b:表示字母数字与非字母数字的边界,非字母数字与字母数字的边界。即下面ve的右边不能有字母和数字
import re
print(re.match(r'.*ve\b','ve.2testaabcd')) #因为在python中\代表转义,所以前面加上r消除转义
print(re.match(r'.*ve\b','ve2testaabcd'))

\B 匹配非单词边界
import re
print(re.match(r'.*ve\B','2testaavebcdve')) #ve的右边需要有字母或者数字
print(re.match(r'.*ve\B','2testaave3bcdve'))

匹配分组

| 匹配左右任意一个表达式
只要|两边任意一个表达式符合要求就行
import re
print(re.match(r'\d[1-9]|\D[a-z]','2233')) #匹配|两边任意一个表达式
print(re.match(r'\d[1-9]|\D[a-z]','as'))

(ab) 将括号中字符作为一个分组
()中的内容会作为一个元组字符装在元组中
import re
a = re.match(r'(.*)','你好啊')
print(a.group()) #输出匹配的字符
print(a.groups()) #会将()中的内容会作为一个元组字符装在元组中
print('
')
b = re.match(r'(.*)()','你好啊')
print(b.groups()) #有两括号就分为两个元组元素
print(b.group(0)) #group中默认是0
print(b.group(1)) #你好啊
print(b.group(2)) #h1
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001183507965.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_13,color_FFFFFF,t_70,g_se,x_16" /></p>
<h1>search</h1>
<p>和match差不多用法,从字符串中进行搜索</p>
<pre><code class="language-python">import re
print(re.match(r'\d\d','123test123test'))
print(re.search(r'\d\d','123test123test'))
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/2021100118400962.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_17,color_FFFFFF,t_70,g_se,x_16" /></p>
<h1>findall</h1>
<p>从字面意思上就可以看到,findall是寻找所有能匹配到的字符,并以列表的方式返回</p>
<pre><code class="language-python">import re
print(re.search(r'test','123test123test'))
print(re.findall(r'test','123test123test')) #以列表的方式返回
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001184302380.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_19,color_FFFFFF,t_70,g_se,x_16" /></p>
<h2>re.s</h2>
<p>findall中另外一个属性re.S</p>
<p>在字符串a中,包含换行符\n,在这种情况下</p>
<ul>
<li>如果不使用re.S参数,则只在每一行内进行匹配,如果一行没有,就换下一行重新开始。</li>
<li>而使用re.S参数以后,正则表达式会将这个字符串作为一个整体,在整体中进行匹配。</li>
</ul>
<p>如下要寻找test.*123的数据,因为test和123在不同的行,如果没加re.s的话,他会在每一个进行匹配查找而不是将字符串作为一个整体进行查找</p>
<pre><code class="language-python">import re
a = """aaatestaa
aaaa123"""
print(re.findall(r'test.*123',a))
print(re.findall(r'test.*123',a,re.S))
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001190037530.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_12,color_FFFFFF,t_70,g_se,x_16" /></p>
<h1>sub</h1>
<p>查找要替换的字符串中的所有匹配数据<details><summary><em><font color='gray'>[En]</font></em></summary><em><font color='gray'>Find all matching data in the string to replace</font></em></details></p>
<blockquote>
<p>sub(要替换的数据,替换成什么,要替换的数据所在的数据)</p>
</blockquote>
<pre><code class="language-python">import re
print(re.sub('php','python','php是世界上最好的语言——php'))
#输出 "python是世界上最好的语言——python"
</code></pre>
<h1>split</h1>
<p>拆分字符串并返回列表<details><summary><em><font color='gray'>[En]</font></em></summary><em><font color='gray'>Splits the string and returns a list</font></em></details></p>
<pre><code class="language-python">import re
s = "itcase,java:php-php3;html"
print(re.split(r",",s)) #以,号进行分割
print(re.split(r",|:|-|;",s)) #以,或者:或者-或者;进行分割
print(re.split(r",|:|-|%",s)) #找不到的分隔符就忽略
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/2021100119082568.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_18,color_FFFFFF,t_70,g_se,x_16" /></p>
<h1>贪婪与非贪婪</h1>
<p>python里的数量词默认是贪婪的,总是尝试尽可能的匹配更多的字符。python中使用?号关闭贪婪模式</p>
<p>如</p>
<pre><code class="language-python">import re
print(re.match(r"aa\d+","aa2323")) #会尽可能多的去匹配\d
print(re.match(r"aa\d+?","aa2323")) #尽可能少的去匹配\d
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001192655487.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_20,color_FFFFFF,t_70,g_se,x_16" /></p>
<pre><code class="language-python">import re
s = "this is a number 234-235-22-423"
# 1.贪婪模式
resule = re.match(r"(.+)(\d+-\d+-\d+-\d)",s) #我们本想数字和字母拆解成两个分组
print(resule.groups()) #('this is a number 23', '4-235-22-4')但我们发现输出的结果中23的数字竟然被弄到前面去了
#因为+它会尽可能多的进行匹配,\d,只需要一个4就能满足,所以前面就尽可能多的匹配
# 2.关闭贪婪模式
#在数量词后面加上 ?,进入非贪婪模式,尽可能少的进行匹配
result = re.match(r"(.+?)(\d+-\d+-\d+-\d)",s)
print(result.groups()) #('this is a number ', '234-235-22-4')
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001192036635.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_16,color_FFFFFF,t_70,g_se,x_16" /></p>
<h1>案例</h1>
<h2>匹配手机号</h2>
<p>要求,手机号为11位,必须以1开头,且第二个数字为35678其种一个</p>
<pre><code class="language-python">import re
result = re.match(r'1[35678]\d{9}','13111111111')
print(result.group()) #匹配成功
result = re.match(r'1[35678]\d{9}','12111111111')
print(result) #none,第二位为2
result = re.match(r'1[35678]\d{9}','121111111112')
print(result) #none,有12位
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001193249688.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_11,color_FFFFFF,t_70,g_se,x_16" /></p>
<h2>提取网页源码中所有的文字</h2>
<p>如下,将其中的所有文字提取出来,去掉标签。思路就是运用sub方法,将标签替换为空</p>
<pre><code class="language-html">s = """
岗位职责:
完成推荐算法、数据统计、界面、后台等服务器端相关工作。<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Complete the server-side related work such as recommendation algorithm, data statistics, interface, background, etc.</font>*</details>
必备要求:
良好的自我驱动力和敬业精神,积极主动,注重结果<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Good self-driving force and professionalism, proactive and result-oriented</font>*</details>
技术要求:
1、一年以上 Python开发经验,掌握面向对象分析和设计,了解设计模式
2、掌握HTTP协议,熟悉NVC、MVVM等概念以及相关wEB开发框架
3、掌握关系数据库开发设计,掌握SQL,熟练使用 MySQL/PostgresQL中的一种
4、掌握NoSQL、MQ,熟练使用对应技术解决方案
5、熟悉 Javascript/cSS/HTML5,JQuery,React.Vue.js
加分项:
大数据,数理统计,机器学习,sklearn,高性能,大并发。
"""
</code></pre>
<p>要提取的最重要的事情是关闭贪婪模式。<details><summary><em><font color='gray'>[En]</font></em></summary><em><font color='gray'>The most important thing to extract is to turn off greed mode.</font></em></details></p>
<pre><code class="language-python">result = re.sub(r'| ','',s) #
print(result)
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/20211001194122230.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_20,color_FFFFFF,t_70,g_se,x_16" /></p>
<p>如果关闭贪婪模式,</p>
<h2>提取图片地址</h2>
<pre><code class="language-python">import re
s = """"""
result1 = re.search(r"src=\"https.*.jpg\"",s)
print(result1.group())
result2 = re.search(r"src=\"(https.*.jpg)\"",s) #我只是想将网址提取出来,所以httpxx加括号,这样我就可以把它单独提取出来,src则不会出来
print(result2.groups()[0])
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/2021100120003865.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCP57yY5Za1fg==,size_20,color_FFFFFF,t_70,g_se,x_16" /></p>
<h2>从字符串中提取指定范围内的字符串</h2>
<h3>案例1</h3>
<p>如想从</p>
<p>"</p>
<p>csrftoken=ZjfvZBcDMcVs7kzYqexJqtKiJXIDxcmSnXhGD1ObR2deuHzaU0FuCxSmh10fSmhf; expires=Thu, 29 Jun 2023 07:59:04 GMT; Max-Age=31449600; Path=/; SameSite=Lax</p>
<p>"</p>
<p>里面提取出token值</p>
<pre><code class="language-python">import re
str = "csrftoken=ZjfvZBcDMcVs7kzYqexJqtKiJXIDxcmSnXhGD1ObR2deuHzaU0FuCxSmh10fSmhf; expires=Thu, 29 Jun 2023 07:59:04 GMT; Max-Age=31449600; Path=/; SameSite=Lax"
a = re.search(r'=(.*?);', str)
print(a.group(1)) #输出匹配的字符
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/img_convert/36acd1a0e7e265c503f33f7193fe26b0.png" /></p>
<h3>案例2</h3>
<p>通过从响应包中提取关键字的行,您可以向规则添加变量<details><summary><em><font color='gray'>[En]</font></em></summary><em><font color='gray'>By extracting the line of the keyword from the response package, you can add variables to the rule</font></em></details></p>
<pre><code class="language-python">import re
key = "威胁"
a = """
很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断。
您的请求ID是:
781bad0a16702307419116917e43b3
"""
res = re.search(r'(.*?%s.*?)'%(key),a,re.S)
print(res.group(1).replace("\n","").replace(" ",""))
</code></pre>
<p><img alt="" src="https://img-blog.csdnimg.cn/img_convert/3b159b1b1c576a4cd7a412961c97e95a.png" /></p>
<blockquote>
<p>Original: https://blog.csdn.net/qq_44159028/article/details/120575621
Author: 山山而川'
Title: Python 正则表达式详解(建议收藏!)</p>
</blockquote>
<hr />
<hr />
<h2><strong>相关阅读</strong></h2>
<h2>Title: dotnet core 也能协调分布式事务啦!</h2>
<blockquote>
<p>2022 年 5 月 24 日,我们发布了 DBPack <a href="release-v0.1.0">v0.1.0</a> 版本,该版本主要 release 了分布式事务功能。在我们的规划里,DBPack 是要支持所有微服务开发语言协调分布式事务的,但经过社区反馈,dotnet core 并不支持。于是,我们在 v0.1.1 对 dotnet core 进行了支持。下面就如何支持 dotnet core 做一个说明。</p>
</blockquote>
<h2>MySql 协议</h2>
<p>先请允许我对 MySql 的通信协议做一个简单的介绍。MySql 支持两种协议,一种是文本(Text)协议,一种是二进制(Binary)协议。MySql 客户端使用 COM_QUERY 发出的请求,MySql 服务端会以文本协议响应结果;使用 COM_STMT_EXECUTE 命令发出的请求,会以二进制协议响应结果。</p>
<p>在我们用程序调用 MySql Client SDK 发起请求的时候,不同的 MySql Client SDK 会默认使用不同的协议发送请求,但大部分 MySql Client SDK 都支持文本协议和二进制协议,我们可以通过修改属性配置改变 MySql Client SDK 的默认行为。比如:</p>
<ul>
<li>JAVA</li>
</ul>
<pre><code class="language-java">@Mapper
public interface ProductMapper {
@Update("UPDATE /*+ XID('${xid}') */
.
SET
available_qty =
available_qty` - #{qty}, allocated_qty = allocated_qty + #{qty} WHERE product_sysno = #{productSysNo} AND available_qty >= #{qty}")
boolean allocateInventory(@Param("xid") String xid, @Param("productSysNo") long productSysNo, @Param("qty") int qty);
}
在 java 语言编写的微服务中,我们写了一个方法去修改商品的库存,当我们传入参数提交执行的时候,默认该 SQL 请求会被编码成
update /*+ XID('gs/aggregationSvc/81336085455405058') */ product.inventory set available_qty = available_qty - 2, allocated_qty = allocated_qty + 2 where product_sysno = 1 and available_qty >= 2;
通过 COM_QUERY 命令发出。
我们可以通过修改连接字符串,在原来的 jdbc:mysql://dbpack2:13307/product
上加上 useServerPrepStmts=true
,改为 jdbc:mysql://dbpack2:13307/product?useServerPrepStmts=true
,再次执行时,会首先发出 COM_STMT_PREPARE 请求:
UPDATE /*+ XID('gs/aggregationSvc/2612341069705662465') */ product.inventory set available_qty = available_qty - ?, allocated_qty = allocated_qty + ? WHERE product_sysno = ? and available_qty >= ?
获取到 statement id 后,再将 statement id 和请求参数编码后通过 COM_STMT_EXECUTE 命令发出。
- Golang
Golang MySql driver 默认是以二进制协议发送带参数的 DML 请求的,通过在 dsn 上加上参数 interpolateParams=true
,才会以文本协议发送。例如:
dksl:123456@tcp(127.0.0.1:13306)/employees?interpolateParams=true&timeout=10s&readTimeout=10s&writeTimeout=10s&parseTime=true&loc=Local&charset=utf8mb4,utf8
Dotnet Core
Dotnet core 如果使用 EntityFrameworkCore 或者 Dapper 来访问数据库,目前还不支持使用 Prepared Statement,下面这两个 issue 有相关说明:
在 v0.1.0 版本,我们只对 COM_STMT_EXECUTE 请求做了拦截处理,来协调分布式事务问题。dotnet core 使用 COM_QUERY 提交请求自然无法协调分布式事务,在 v0.1.1 我们增加了 COM_QUERY 请求协调分布式事务的支持,这样真正做到了支持所有微服务语言协调分布式事务。
其他特性
本次发版,还修复了一些 bug,增加了 status api 用于查询 dbpack 的运行状态:
$ curl http://localhost:9999/status
$ {
"listeners": [{
"protocol_type": "mysql",
"socket_address": {
"address": "0.0.0.0",
"port": 13306
},
"active": true
}],
"distributed_transaction_enabled": true,
"is_master": true
}
至此,我们有了
- /live
- /ready
- /status
- /metrics
这些 api 辅助我们查看 dbpack 的运行状态。
在下一个版本,我们会增加 tracing 和审计日志的功能。
一些链接
Original: https://www.cnblogs.com/DKSL/p/16358143.html
Author: Scott Lewis
Title: dotnet core 也能协调分布式事务啦!
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/280306/
转载文章受原作者版权保护。转载请注明原作者出处!