• [技术干货] 【技术长文】编译原理——正则表达式和有穷自动机(DFA与NFA)的关系
    NFA 和 DFA浅析—要深入了解正则表达式,必须首先理解有穷自动机。有穷自动机(Finite Automate)是用来模拟实物系统的数学模型,它包括如下五个部分:有穷状态集States输入字符集Input symbols转移函数Transitions起始状态Start state接受状态Accepting state(s)(终止状态)下图为一台有穷自动机可以看到,该自动机包含四个状态(有限状态)q0, q1, q2, q3,两个输入字符a, b,转移函数如图所示,起始状态为q0,接受状态为q3。有穷自动机,按照转移函数的不同,又可分为确定型有穷自动机(Determinism Finite Automate, DFA),与非确定型有穷自动机(Non-determinism Finite Automate, NFA)。  非确定有穷自动机容许转移函数不确定,换句话说,对任意状态,输入任意一个字符,可以转移到0个,1个或者多个状态。下图是一台非确定有穷自动机,可以看到,对状态q0输入字符a,既可以转移到q0,也可以转移到q1,这就是“非确定”的意义所在。对某个自动机来说,如果从起始状态,接受一系列输入字符,可以转移到接受状态,即认为这一系列字符可以被自动机接受。  如果两台自动机能够接受的输入字符串(或者叫做“正则语言”Regular Language)完全相同,则这两台自动机是等价的。可以证明,对于每一个非确定有穷自动机,都存在与之等价的确定型有穷自动机(证明略)。正则表达式就是建立在自动机的理论基础上的:用户写完正则表达式之后,正则引擎会按照这个表达式构建相应的自动机(可能是NFA,也可能是DFA,但它们必定是等价的),若输入一串文本之后,自动机抵达了接受状态,则这串文本可以“匹配”用户指定的正则表达式。下面是同一个正则表达式 a|ab 对应的NFA和DFA在Mastering Regular Expression中,Friedl首先分析了NFA和DFA的区别,DFA比较快,但不提供Backtrack(回溯)功能,NFA比较慢,但提供了Backtrack功能。在分析两种引擎的匹配过程时,Friedl指出,NFA是基于表达式的(Regex-Directed),而DFA是基于文本的(Text-Directed)。举例来说,对于正则表达式 to(nite|knight|night),NFA在匹配最开始两个字符(to)之后,剩下的三个组件(component)是 nite, knight 和 night,于是正则引擎会依次尝试这三个选择分支(每次尝试一个);而DFA在匹配最开始两个字符之后,会将剩下的三个选择拆分作字符,并行尝试,也就是说,匹配 to 之后,先匹配 k 或者 n ,如果 k 不能匹配,则放弃 knigth 所在的分支,再匹配 i ,再匹配 t 或 g ……这样继续下去,直到匹配结束。不幸的是,Friedl对匹配过程的分析,是完全错误的——引擎的不同,是指构建的自动机的不同,而不是匹配算法的不同!DFA引擎在任意时刻必定处于某个确定的状态,而NFA引擎可能处于一组状态之中的任何一个,所以,NFA引擎必须记录所有的可能路径(trace multiple possible routes through the NFA),NFA之所以能够提供Backtrack的功能,原因就在这里。  传统的NFA匹配算法是带回溯的深度优先搜索(backtracking depth-first search,就是上文所说的Regex-Based过程),而新的PCRE算法提供了效率更高的广度优先搜索,可以同时保持所有可能的NFA状态(请参考http://www.cl.cam.ac.uk/Teaching/current/RLFA/,尤其是Lecture Notes的section 2.2)。Friedl的错误就在这里,他混淆了应用PCRE算法的NFA与DFA的匹配过程。需 要指出的是,即使应用PCRE算法,NFA的速度仍然低于DFA,这是由NFA需要同时保存多种可能的性质决定的。从理论上说,如果我们不需要应用 Backtrack,完全可以从NFA构造出等价的DFA,再进行匹配,这样能大大提高速度——代价是,DFA需要更多的空间。转自:https://blog.csdn.net/lilongsy/article/details/82465786
  • [技术干货] 【技术长文】编译原理——词法分析器
    基本定义词法分析的第一阶段即扫描器,通常基于有限状态自动机。扫描器能够识别其所能处理的标记中可能包含的所有字符序列(单个这样的字符序列即前面所说的“语素”)。例如“整数”标记可以包含所有数字字符序列。很多情况下,根据第一个非空白字符便可以推导出该标记的类型,于是便可逐个处理之后的字符,直到出现不属于该类型标记字符集中的字符(即最长一致原则)。词法分析器的工作是低级别的分析:将字符或者字符序列转化成记号。在谈论词法分析时,使用术语“词法记号”(简称记号)、“模式”和“词法单元”表示特定的含义。在分析时,一是把词法分析器当成语法分析的一部分,另一种是把词法分析器当成编译程序的独立部分。在前一种情况下,词法分析器不断地被语法分析器调用,每调用一次词法分析器将从源程序的字符序列拼出一个单词,并将其Token值返回给语法分析器。后一种情况则不同,词法分析器不是被语法分析器不断地调用,而是一次扫描全部单词完成编译器的独立一遍任务。制作一个简单的词法分析器定义如下:(1)保留字int   void   if   else   return   while   正则表达式即为原串,在代码中当作标识符匹配,匹配完后再与保留字比较(2)标识符letter = [a-z | A-Z]digit = [0-9]正则表达式 letter (letter | digit )*(3)数字digit = [1-9]D = 0 | digit整型:正则表达式:digit D*浮点型:正则表达式:digit (. D*)? (e -? digit D*)?(4)符号+   -   *   /   %   >   >=   <   <=   [   ]   (   )   {   }   !=   ==    ,    ;正则表达式即符号本身(5)注释C = 所有字符//型:正则表达式:// C*/**/型:正则表达式:/* C* */代码实现:  父类:class Scanner { private: std::string buffer; int pos; //缓冲区位置 int syn; //token类别 int state; //DFA中的状态 std::string sourcename; int filepos; std::ifstream infile; //int tsss; const int BUFFERLENGTH = 4096; public: Scanner(const char* s) { sourcename = s; infile.open(s); pos = 0; syn = -1; state = 0; filepos = 0; } void GetToken(); //在DFA上转移,识别token bool IsNum(const char c); bool IsLetter(const char c); char GetNext(); //获取下一个字符 void Back(); //向前看完后回溯 ~Scanner() { infile.close(); } };    子类:oid Scanner::GetToken()      代码过多,不予以全部展示 bool Scanner::IsNum(const char c) bool Scanner::IsLetter(const char c) char Scanner::GetNext() void Scanner::Back()测试用例:int gcd (int u, int v) { if (v == 0) return u ; else return gcd(v,u-u/v*v); } void main(void) { int x; int y; x = input(); y = input(); output(gcd(x,y)); }测试结果:
  • [技术干货] 从字符串中取出特定的某个字符串(使用正则表达式获取)
        //定义字符串var str1 = '# abc 1234we # abc 456we # abc 789qwe'//正则表达式,获取str1字符串中1234we,456we,789qwevar key = /abc (.\d\s\w\-_)///执行正则表达式content = content.match(key)
  • Jmeter系列(27)- 详解正则提取器
    有了 JSON 提取器为啥还要用正则提取器?JSON 提取器只针对接口返回的响应内容如果想提取的是响应头、请求头的值,而非响应内容的值呢?这个时候正则提取器的作用就出来了,它可以提取请求任一部分的值 需知正则表达式很多内容,在这篇文章中不会展开详细说的哦,主要还是说提取器的使用 正则提取器我们通过实际栗子去讲述理论知识点 正则提取器界面介绍 字段含义字段含义Apply to应用范围,选默认的 main sample only 就行了Field to check可提取的字段Names of created variables接收提取值的变量名必传Regular Expression正则表达式Template从找到的匹配项中创建字符串的模板Match No.(0 for Random)取第几个值0:随机,默认-1:所有1:第一个值非必传Default Value缺省值,匹配不到值的时候取该值非必传Use empty default value勾选后,提取不到值时,则返回空字符串 Template如果一条正则表达式有多个提取结果,则提取结果是数组形式模板 $1$、$2$.....表示把解析到的第几个值赋给变量,从 1 开始匹配$0$ 表示整个表达式匹配的内容(后续具体看栗子)若只有一个结果,只能是$1$ Field to check属性含义Body响应体,不包括响应头;最常用Body (unescaped)响应体,替换了所有HTML转义符;不建议使用Body as a Document从不同类型的文件中提取文本;影响性能Request Headers请求头Response Headers响应头URLURLResponse Code响应码Response Message响应信息 Body Request Headers Response Headers URL Response Code、Message 入门栗子栗子的前提这个栗子,我都会以这个地址的接口来完成 JSON 提取器的实战栗子,大家可以注册个账号玩一玩哦 测试计划树结构下面多个栗子都以这个测试计划为基础哦 提取某个特定的值的栗子登录接口响应登录是执行其他接口的前置接口,所以要获取用户登录后的 token、uuid 提取 token 提取 uuid 其他接口调用 token、uuid 知识点提其他接口可以通过  ${var}  这种格式,来获取提取到的值 ( ) 里面写匹配规则,用于解析正则表达式 .*? 表示匹配任意长度的任意字符,这也是最常用的正则表达式一般 (.+?) 和 (.*?) 能够满足我们 80%的使用场景 一般正则表达式都可以写成下面两种 左边界(.+?)右边界  左边界(.*?)右边界  举更多栗子前的一些话上面讲的是使用正则提取器时的一个流程,也是实际工作中最简单的栗子在实际项目中,我们可能会出现一条正则表达式有多个提取结果的情况 JSON 字符串下面的栗子都以这个 JSON 字符串为基础,从里面提取结果这 JSON 字符串也是某个接口的响应内容,货真价实,感兴趣也可以自己玩一玩:http://api.yesapi.cn/docs-api-App.User.GetList.html{ "ret": 200, "msg": "V2.5.1 YesApi App.User.GetList", "data": { "total": 4, "err_msg": "", "err_code": 0, "users": [ { "role": "user", "status_desc": "正常", "reg_time": "2020-06-22 20:45:05", "role_desc": "普通会员", "ext_info": { "yesapi_nickname": "", "yesapi_points": 0 }, "uuid": "0564CE592B4CE914365D8922F6FC4CEC", "username": "luojunjiess286", "status": 0 }, { "role": "user", "status_desc": "正常", "reg_time": "2020-06-22 14:27:17", "role_desc": "普通会员", "ext_info": { "yesapi_nickname": "", "yesapi_points": 0 }, "uuid": "0164DC0680F84DCE40D3DD4A36640ECA", "username": "luojunjiessa", "status": 0 }, { "role": "admin", "status_desc": "正常", "reg_time": "2020-03-23 22:48:32", "role_desc": "管理员", "ext_info": { "yesapi_nickname": "", "yesapi_points": 0 "yesapi_reg_source": "" }, "uuid": "079BF6BB82AFCFC7084F96AECAF0519F", "username": "luojunjiess", "status": 0 } ] } } 一条正则表达式只有一个提取结果的栗子什么叫只有一个提取结果就是正则表达式里只有一个 ( ) ,且  Match No. 不是 -1 未填写模板提取器 测试结果uuid1= uuid1_g=1 uuid1_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC" uuid1_g1=0564CE592B4CE914365D8922F6FC4CEC 知识点如果正则匹配到值,但是没有填模板,则返回空 $0$提取器 测试结果uuid2="uuid":"0564CE592B4CE914365D8922F6FC4CEC" uuid2_g=1 uuid2_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC" uuid2_g1=0564CE592B4CE914365D8922F6FC4CEC 知识点 $0$ 模板其实返回的就是 uuid2_g0 的值返回了整个正则表达式,不只是 ( ) 内匹配到的值 $1$提取器 测试结果uuid3=0564CE592B4CE914365D8922F6FC4CEC uuid3_g=1 uuid3_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC" uuid3_g1=0564CE592B4CE914365D8922F6FC4CEC 知识点 $1$  模板其实返回的就是 uuid2_g1 的值仅返回 ( ) 内匹配到的值 $2$提取器 测试结果uuid4=null uuid4_g=1 uuid4_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC" uuid4_g1=0564CE592B4CE914365D8922F6FC4CEC 知识点 $2$ 模板并不存在,其实就是 uuid4_g2 变量不存在,即使勾了使用空默认值,也返回 null, 总结其实 uuid 在 JSON 字符串中有三个可匹配到的值,如果不填写匹配数字 Match No. ,则会随机取一个 uuid 并返回像上述的几个栗子,都填了 1 ,所以都返回了第一个匹配到的 uuid 一条正则表达式有多个提取结果的栗子什么叫有多个提取结果有两种情况一条表达式有多个 ( ) 一个 ( ) 匹配到多个值,且 Match No 填了 -1 一个 ( ) 匹配到多个值 提取器 测试结果手动分成四部分uuid1_1=0564CE592B4CE914365D8922F6FC4CEC uuid1_1_g=1 uuid1_1_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC" uuid1_1_g1=0564CE592B4CE914365D8922F6FC4CEC uuid1_2=0164DC0680F84DCE40D3DD4A36640ECA uuid1_2_g=1 uuid1_2_g0="uuid":"0164DC0680F84DCE40D3DD4A36640ECA" uuid1_2_g1=0164DC0680F84DCE40D3DD4A36640ECA uuid1_3=079BF6BB82AFCFC7084F96AECAF0519F uuid1_3_g=1 uuid1_3_g0="uuid":"079BF6BB82AFCFC7084F96AECAF0519F" uuid1_3_g1=079BF6BB82AFCFC7084F96AECAF0519F uuid1_matchNr=3 知识点一个 ( ) 匹配到多个值的场景 ,一般会结合 ForEach控制器,可以循环将提取到的值赋予到 HTTP 请求中可以看看下图的小栗子,这里不展开讲,后面会再详细讲解 结构树 + ForEach 控制器 查看结果树 一条表达式有多个( ),且模板为空提取器 测试结果info1= info1_g=2 info1_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC","username":"luojunjiess286" info1_g1=0564CE592B4CE914365D8922F6FC4CEC info1_g2=luojunjiess286 一条表达式有多个( ),且只有一个模板提取器 测试结果info2=0564CE592B4CE914365D8922F6FC4CEC info2_g=2 info2_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC","username":"luojunjiess286" info2_g1=0564CE592B4CE914365D8922F6FC4CEC info2_g2=luojunjiess286 知识点info2 拿的就是 info2_g1 的值 $1$ 获取的是第一个 ( ) 匹配到的值, $2$ 获取的是第二个 ( ) 匹配到的值,以此类推      一条表达式有多个( ),且有两个模板提取器 测试结果info3=0564CE592B4CE914365D8922F6FC4CECluojunjiess286 info3_g=2 info3_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC","username":"luojunjiess286" info3_g1=0564CE592B4CE914365D8922F6FC4CEC info3_g2=luojunjiess286 info4=0564CE592B4CE914365D8922F6FC4CEC,luojunjiess286 info4_g=2 info4_g0="uuid":"0564CE592B4CE914365D8922F6FC4CEC","username":"luojunjiess286" info4_g1=0564CE592B4CE914365D8922F6FC4CEC info4_g2=luojunjiess286 
  • [技术干货] java干活分享之正则表达式
    用途:正则表达式用来定义字符串模式、还可以用来搜索 编辑 处理文本。什么是正则表达式呢?其实一个字符串就是一个简单的正则表达式  如:hello java 匹配到的正则表达式就”hello java“  那就有人问了 特殊符号例如 点号 .  也是正则表达式么?回答是对的点号匹配到的字符 如 "a" 或"1"举例: this is java 匹配字符串 "this is java"            this\s+is\s+java 注意字符串中的\s+ 匹配单词this后面的\s可以匹配多个空格 之后匹配is字符串 在之后\s匹配多个空格然后在跟上java字符串            匹配结果:this is java           ^\d+(\.\d+)?  ^定义了以什么开始  \d匹配一个或多个数字 ?设置括号内的选项是可选的  \匹配""  可以匹配的例子:  "5","1.5","3.8"学过perl的都知道其实java 的正则表达式和perl是最为相似的java util regex包主要包括以下三个类:pattern类:              作用:pattern对象是一个正则表达式的编译。pattern类没有公共的构造方法 要创建一个pattern对象 必须先调用其公共静态编译方法 它返回一个pattern对象 该方法接受一个正则表达式的参数matcher类:             作用:matcher对象是对输入字符串进行解释和匹配操作的引擎 与pattern类一样 matcher也没有公共的构造方法  需要调用pattern对象的matcher方法获得一个matcher对象patternsyntaxexception            作用:其是一个非强制的异常类  它表示一个正则表达式模式中的语法错误举个例子吧:学过正则表达式的知道名词:捕捉组捕捉组是把多个字符当一个单独的单元进行处理的方法它提供对括号内的字符分组来创建例如:正则表达式(cat)创建了一个单一分组  组内包含:"d"  "o"  "g"捕捉组通过从左至右计算其开括号来编号例如 ((A)(B)(C))有这样四个分组:(A)  ((A)(B)(C)) )(B)(C)  (C)  可以通过调用matcher对象的groupcount 方法来查看表达式到底分了多少组  groupcount 方法返回一个int值  表示matcher对象当前有多个捕捉组还有一个特殊的组group(0) 它总是代表整个表达式 该组不包括在groupcount的返回值中举个实例:正则表达式语法:在其他语言中,\\表示我想要在这边负责vu挨打事故这个i部分插入一个普通的反斜杠 请不要给他任何特殊的意义;(其实就是c语言中的转义字符)在java中\\表示我要插入一个正则表达式的反斜杠,所以后面的字符有特殊的意义所以在其他的语言中 如 c  pert  一个反斜杠就足以具有转义的作用 而在java中正则表达式中则需要有俩个反斜杠菜鸟被解析为其他语言中的转义作用。这就是为什么表示一位数字的正则表达式是\\d而 表示一个普通的反斜杠是\\\\索引方法:pubilc int start()  返回以前匹配的初始索引public int start(int group) 返回在以前的匹配操作期间 由给定组所捕获的子序列的初始索引public int end()返回最后匹配字符之后的偏移量public int end(int group) 返回在以前的匹配操作期间由给定组所捕获子序列的最后字符之后的偏移量举例:那第三期的java之正则表达式就到此结束啦~喜欢的小伙伴点赞加收藏~
  • [技术干货] 如何使用正则匹配最后一个字符串详解
    前几天遇到一个需求,输入的是123456789<user>    <user>        <name>a</name>    </user>    <user>        <name>a</name>    </user></user><password>123</password>要求拿到12345678<user>    <user>        <name>a</name>    </user>    <user>        <name>a</name>    </user></user>也就是去掉最后一个</user>后面的字符串。方法有很多,我首先想到的是用正则匹配去掉</user>后面的字符串。最后写出来的表达式是(?<=</user>)(?![\w\W]*</user>)[\w\W]+。首先用(?<=</user>)匹配所有前面是</user>的位置,如图,总共有三个位置。这里我们正则表达式(?<=</user>)的意思就是匹配的位置之前的字符串是</user>,也就是我们匹配到的位置在</user>之后。这里用到了正则表达式语法中的断言,有的书上也称该语法为预查或者环视,都是一样的用法。有如下语法:(?=pattern) 零宽正向先行断言 (?!pattern) 零宽负向先行断言 (?<=pattern) 零宽正向后行断言 (?<!pattern) 零宽负向后行断言这里用到的是(?<=pattern),零宽表示它匹配的是在字符串中的位置,如同^匹配字符串串首,$匹配字符串串尾。正向代表它必须满足pattern。后行代表它匹配的位置在pattern之后。其次,再这三个位置上进行筛选,能够看出这三个位置的区别是后面是否有</user>,如果没有的话那么它就是最后一个</user>后面的位置。在之前的表达式后面添上(?![\w\W]*?</user>)此时表达式变为(?<=</user>)(?![\w\W]*?</user>)。最后,在之前的正则表达式后面加上[\w\W]+贪婪匹配即尽可能多的匹配该位置后面的字符串。最终的正则表达式是(?<=</user>)(?![\w\W]*?</user>)[\w\W]*最后的最后用四张图简单地描述四种断言的不同之处。这里输入的字符串都是123456。(?=3),它匹配的位置是后面的字符为3的位置。 (?<=3),它匹配的位置是前面的字符为3的位置。 (?!3)匹配的位置是后面的字符不为3的位置,可以看到箭头所指的地方没有被匹配到,其他位置都被匹配到了。(?<!3)匹配的位置是前面的字符不为3的位置,可以看到箭头所指的地方没有被匹配到,其他位置都被匹配到了。能够看到得到了最后一个匹配结果。这里的正则表达式(?!pattern) 是零宽负向先行断言,也就是它会往后匹配pattern,匹配到的位置在pattern之前,并且匹配到的字符串必须不满足pattern。(?![\w\W]*?</user>)的意思是在匹配到的位置后面必须不是[\w\W]*?</user>,\w匹配的是[a-zA-Z0-9_]即匹配字母数字和下划线,而\W匹配的是[^a-zA-Z0-9_]即不是字母数字也不是下划线的字符,同时匹配这两个就相当于匹配任意字符。[\w\W]后面的*代表匹配0-任意多次,后面的?代表懒惰模式,即只要满足条件就立即返回。
  • [新手课堂] Java正则表达式使用
    Java使用正则表达式对手机号相关的字符串进行操作代码示例(代码注释超详细~)import java.util.regex.Matcher;import java.util.regex.Pattern;public class RegexTest{    public static void testphone() {        //手机号正则表达式(未要求字符串为11位,如需要在正则表达式前加入“^”,在正则表达式末尾加入“$”)        String reg = "(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}";        String phone = "13393518460rtyerty18293518460rrt";        Pattern p = Pattern.compile(reg);  //编译正则表达式        Matcher m = p.matcher(phone);  //正则表达式进行字符串匹配        while(m.find()) {            System.out.println(m.start()+" "+m.end());  //输出匹配的字符串的首索引和尾索引(前开后闭)            System.out.println(m.group());        //group()输出匹配的字符串        }        // 注意find()函数使用后索引自动移到下一匹配字符串位置,上面输出匹配子串后故需要重新模式匹配        m = p.matcher(phone);  //正则表达式进行字符串匹配        boolean rs1 = m.find();  //find()方法输出是否匹配成功(无需匹配全部字符串)        System.out.println(rs1);        boolean rs2 = m.matches();  //matches()方法输出是否匹配成功(匹配全部字符串)        System.out.println(rs2);        phone=phone.replaceAll(reg,"\\*$0\\*");  // 将匹配到的字符串进行替换,$0表示匹配的字符串自身        System.out.println(phone);        //如果正则表达式有分组,使用"()"表示,则group(i)可以得到分组匹配到的信息,例如号码前三位前缀采用分组,分组得到“133”和“182”两个满足条件的前缀        m = p.matcher(phone);        while(m.find()) {            System.out.println(m.group(1));        }    }    public static void main(String[] args){        testphone();    }}
  • [技术干货] Python常用正则表达式笔记分享
    正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1.5版本起增加了 re 模块,是用于处理字符串的强大工具,re 模块使 Python 语言拥有全部的正则表达式功能。compile() 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。本章节主要介绍Python中常用的正则表达式处理函数。re.match函数re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。函数语法:re.match(pattern, string, flags=0)函数参数说明:参数描述pattern匹配的正则表达式string要匹配的字符串。flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。正则表达式修饰符 - 可选标志正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:修饰符描述re.I使匹配对大小写不敏感re.L做本地化识别(locale-aware)匹配re.M多行匹配,影响 ^ 和 $re.S使 .匹配包括换行在内的所有字符re.U根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.re.X该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。匹配成功re.match方法返回一个匹配的对象,否则返回None。我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。匹配对象方法描述group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。实例import re​print(re.match('www', 'www.python.org').span())  # 在起始位置匹配print(re.match('org', 'www.python.org'))         # 不在起始位置匹配以上实例运行输出结果为:(0, 3)None实例import re line = "Cats are smarter than dogs" matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) if matchObj:   print ("matchObj.group() : ", matchObj.group())   print ("matchObj.group(1) : ", matchObj.group(1))   print ("matchObj.group(2) : ", matchObj.group(2))else:   print ("No match!!")以上实例执行结果如下:matchObj.group() : Cats are smarter than dogsmatchObj.group(1) : CatsmatchObj.group(2) : smarterre.search 方法re.search 扫描整个字符串并返回第一个成功的匹配。函数语法:re.search(pattern, string, flags=0)函数参数说明:参数描述pattern匹配的正则表达式string要匹配的字符串flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等匹配成功re.search方法返回一个匹配的对象,否则返回None。 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。匹配对象方法描述group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。实例import re​print(re.search('www', 'www.python.org').span())  # 在起始位置匹配print(re.search('org', 'www.python.org').span())  # 不在起始位置匹配以上实例运行输出结果为:(0, 3)(11, 14)实例import re line = "Cats are smarter than dogs"; searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I) if searchObj: print ("searchObj.group() : ", searchObj.group()) print ("searchObj.group(1) : ", searchObj.group(1)) print ("searchObj.group(2) : ", searchObj.group(2)) else: print ("Nothing found!!")以上实例执行结果如下:searchObj.group() : Cats are smarter than dogs searchObj.group(1) : Cats searchObj.group(2) : smarterre.match 与 re.search 的区别re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。实例import re line = "Cats are smarter than dogs"; matchObj = re.match( r'dogs', line, re.M|re.I) if matchObj: print ("match --> matchObj.group() : ", matchObj.group()) else: print ("No match!!") matchObj = re.search( r'dogs', line, re.M|re.I) if matchObj: print ("search --> matchObj.group() : ", matchObj.group()) else: print ("No match!!")以上实例运行结果如下:No match!! search --> matchObj.group() : dogs检索和替换Python 的 re 模块提供了 re.sub 用于替换字符串中的匹配项。语法:re.sub(pattern, repl, string, count=0)参数:pattern : 正则中的模式字符串。repl : 替换的字符串,也可为一个函数。string : 要被查找替换的原始字符串。count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。实例import re phone = "2004-959-559 # 这是一个电话号码" # 删除注释 num = re.sub(r' #.*$', "", phone) print ("电话号码 : ", num) # 移除非数字的内容 num = re.sub(r'\D', "", phone) print ("电话号码 : ", num)以上实例执行结果如下:电话号码 : 2004-959-559 电话号码 : 2004959559re.compile 函数compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。语法格式为:re.compile(pattern[, flags])参数:pattern : 一个字符串形式的正则表达式flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:re.I 忽略大小写re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境re.M 多行模式re.S 即为' . '并且包括换行符在内的任意字符(' . '不包括换行符)re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库re.X 为了增加可读性,忽略空格和' # '后面的注释实例>>> import re >>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字 >>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配 >>> print m None >>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配 >>> print m None >>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配 >>> print m # 返回一个 Match 对象 <_sre.SRE_Match object at 0x10a42aac0> >>> m.group(0) # 可省略 0 '12' >>> m.start(0) # 可省略 0 3 >>> m.end(0) # 可省略 0 5 >>> m.span(0) # 可省略 0 (3, 5)在上面,当匹配成功时返回一个 Match 对象,其中:group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group()或 group(0);start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;span([group]) 方法返回 (start(group), end(group))。实例>>> import re >>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写 >>> m = pattern.match('Hello World Wide Web') >>> print(m) # 匹配成功,返回一个 Match 对象 <_sre.SRE_Match object at 0x10bea83e8> >>> m.group(0) # 返回匹配成功的整个子串 'Hello World' >>> m.span(0) # 返回匹配成功的整个子串的索引 (0, 11) >>> m.group(1) # 返回第一个分组匹配成功的子串 'Hello' >>> m.span(1) # 返回第一个分组匹配成功的子串的索引 (0, 5) >>> m.group(2) # 返回第二个分组匹配成功的子串 'World' >>> m.span(2) # 返回第二个分组匹配成功的子串 (6, 11) >>> m.groups() # 等价于 (m.group(1), m.group(2), ...) ('Hello', 'World') >>> m.group(3) # 不存在第三个分组 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: no such groupfindall在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。注意: match 和 search 是匹配一次 findall 匹配所有。语法格式为:re.findall(pattern, string, flags=0)参数:参数描述pattern匹配的正则表达式string要匹配的字符串。flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。查找字符串中的所有数字:实例import re result1 = re.findall(r'\d+', 'TechLab 123 google 456') result2 = re.findall(r'\d+', 'Tech88Lab123google456') print(result1) print(result2)输出结果:['123', '456'] ['88', '123', '456']re.finditer和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。re.finditer(pattern, string, flags=0)参数:参数描述pattern匹配的正则表达式string要匹配的字符串。flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。实例import re it = re.finditer(r"\d+","12a32bc43jf3") for match in it: print (match.group())输出结果:12 32 43 3re.splitsplit 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:re.split(pattern, string[, maxsplit=0, flags=0])参数:参数描述pattern匹配的正则表达式string要匹配的字符串。maxsplit分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。实例>>> import re >>> re.split('\W+', 'python, python, python.') ['python', 'python', 'python', ''] >>> re.split('(\W+)', ' python, python, python.') ['', ' ', 'python', ', ', 'python', ', ', 'python', '.', ''] >>> re.split('\W+', ' python, python, python.', 1) ['', 'python, python, python.'] >>> re.split('a*', 'hello world') # 对于一个找不到匹配的字符串而言,split 不会对其作出分割 ['hello world']附录正则表达式对象re.RegexObjectre.compile() 返回 RegexObject 对象。re.MatchObjectgroup() 返回被 RE 匹配的字符串。start() 返回匹配开始的位置end() 返回匹配结束的位置span() 返回一个元组包含匹配 (开始,结束) 的位置正则表达式模式模式字符串使用特殊的语法来表示一个正则表达式:字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。多数字母和数字前加一个反斜杠时会拥有不同的含义。标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。反斜杠本身需要使用反斜杠转义。由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如r'\t',等价于\\t )匹配相应的特殊字符。下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。模式描述^匹配字符串的开头$匹配字符串的末尾。.匹配任意字符,除了换行符,当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个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。正则表达式使用实例字符匹配实例描述python匹配 "python".字符类实例描述[Pp]ython匹配"Python" 或"python"rub[ye]匹配 "ruby" 或 "rube"[aeiou]匹配中括号内的任意一个字母[0-9]匹配任何数字。类似于[0123456789][a-z]匹配任何小写字母[A-Z]匹配任何大写字母[a-zA-Z0-9]匹配任何字母及数字[^aeiou]除了a e i o u字母以外的所有字符[^0-9]匹配除了数字外的字符特殊字符类实例描述.匹配除 \n之外的任何单个字符。要匹配包括\n在内的任何字符,请使用像[.\n]的模式。\d匹配一个数字字符。等价于[0-9]。\D匹配一个非数字字符。等价于[^0-9]。\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。\S匹配任何非空白字符。等价于[^ \f\n\r\t\v]。\w匹配包括下划线的任何单词字符。等价于[A-Za-z0-9_]。\W匹配任何非单词字符。等价于[^A-Za-z0-9_]。
  • [SQL] GaussDB(DWS)的正则表达式知多少
    【摘要】 GaussDB(DWS)除了支持标准的POSIX正则表达式句法,还拥有一些特殊句法和选项,这些你可了解?本文便为你讲解这些特殊句法和选项。概述正则表达式(Regular Expression,简称RE),通常被用来检索、替换那些符合某个模式(规则)的文本。正则表达式使用比较灵活,功能强大,因此经常被用到进行文本的搜索和替换中,帮助开发人员快速进行批量文本查询和处理。比如常用的linux的grep命令,许多程序设计语言比如Perl、Tcl也都支持正则表达式进行字符串操作。GaussDB(DWS)支持的正则表达式POSIX 1003.2中定义的正则表达式RE有两种形式:扩展RE或ERE(大致为egrep的RE),和基本RE或BRE(大致为ed的RE),GaussDB(DWS)都支持这两种形式,并实现了在编程语言(如Perl和Tcl)中广泛使用而POSIX标准中未包含的一些扩展。使用这些非POSIX扩展的RE在本文中称为高级RE或ARE。ARE几乎是ERE的超集,但是BRE有几种符号不相容性(而且是有限的)。GaussDB(DWS)的正则表达式的主要句法和在其他程序语言中支持的句法功能相同,此文不再赘述。本文中对GaussDB(DWS)拥有的特殊形式和句法进行说明。GuassDB(DWS)支持的正则表达式函数GaussDB(DWS)提供了支持POSIX正则表达式的函数,如表1所示。表1  GaussDB(DWS)中的正则表达式函数函数返回类型描述参数说明regexp_replace(string text, pattern text, replacement text [, flags text])Text提供了将匹配POSIX正则表达式模式的子串替换为新文本的功能string:待处理的源字符串pattern:一个正则表达式REreplacement:用此字符串替换原字符串中匹配的部分flags:可选参数,具体取值参见表2regexp_matches(string text, pattern text [, flags text])setof text[]返回一个文本数组,该数组由匹配一个POSIX正则表达式模式得到的所有被捕获子串构成regexp_split_to_table(string text, pattern text [, flags text])setof text把一个POSIX正则表达式模式当作一个定界符来分离一个串regexp_split_to_array(string text, pattern text [, flags text ])text[]和regexp_split_to_table类似,是一个正则表达式分离函数,不过它的结果以一个text数组的形式返回从表1中看到,GuassDB(DWS)支持的正则表达式函数都有一个可选的flags参数,该参数的可选项及其含义是什么呢?下面将展开进行详细举例说明。GaussDB(DWS)正则表达式函数的flags参数详解表2中列举了表1中flags参数的所有可选项。表2  GaussDB(DWS)正则表达式函数的flags参数的选项说明选项描述bRE是一个BRE,表示按照BRE匹配模式的规则进行匹配c大小写敏感匹配 (是一个可被覆盖的操作符类型)g表示替换每一个匹配的子字符串而不仅仅是第一个。默认仅替换第一个匹配的子字符串i大小写不敏感匹配(是一个可被覆盖的操作符类型)m和选项n同义n换行敏感匹配,此选项生效时,换行符影响元字符(.、^、$和[^)的匹配p部分换行敏感匹配,此选项生效时,换行符影响元字符(.和[^)的匹配。部分是相对选项n而言qRE被认为是加双引号的文本字符串,所有字符都是普通字符s非换行敏感匹配(默认),与n相对t紧凑语法(默认)w反部分换行敏感匹配,此选项生效时,换行符影响元字符(^和$)的匹配。部分是相对选项n而言x扩展语法表2中给出的flags参数选项描述,非常简洁,理解起来比较困难。下面通过一些示例,来直观帮助理解上面这些flags参数选项的含义。g选项示例1-1:未指定’g‘选项,仅对第一个匹配项进行替换示例1-2:指定’g‘选项,对所有匹配项进行替换c 和 i 选项示例2-1:默认情况下,进行大小写敏感匹配示例2-2:显示指定进行大小写敏感匹配示例2-3:显示指定进行大小写不敏感匹配 n[或m]、s、p、w选项对元字符点(.)的影响示例3-1:指定选项n时,元字符点(.)不匹配换行符示例3-2:指定选项s时,元字符点(.)匹配换行符示例3-3:指定选项p时,元字符点(.)不匹配换行符示例4-4:指定选项w时,元字符点(.)匹配换行符n[或m]、s、p、w选项对元字符^、$的影响示例5-1:指定选项n时,元字符点^、$匹配行首和行尾示例5-2:指定选项s时,元字符点^、$不匹配行首和行尾示例5-3:指定选项p时,元字符点^、$不匹配行首和行尾示例5-4:指定选项w时,元字符点^、$匹配第一个行首匹配的行到最后一个行尾匹配的行 n[或m]、s、p、w选项对元字符 [^ 的影响示例6-1:指定选项n时,换行符不匹配被[^排除的字符,所有行尾的换行符未被替换为M示例6-2:指定选项s时,换行符匹配被[^排除的字符,所有行尾的换行符被替换为M示例6-3:指定选项p时,换行符不匹配被[^排除的字符,所有行尾的换行符被替换为M示例6-4:指定选项w时,换行符匹配被[^排除的字符,所有行尾的换行符被替换为M t 和 x 选项通常情况下,RE语法都是严格的,即RE中的所有字符都是重要的。严格语法是默认的,也可以通过指定选项t表示。示例6-1:在严格语法中,空白字符也是重要的GaussDB(DWS)还有一个扩展语法,通过指定x选项表示。在扩展语法中,RE中的空白字符(在这里,空白是空格、水平制表符、新行、和任何属于space字符类的字符。)将被忽略,以及#和换行符(或RE的结尾)之间的所有字符也将被忽略。这种语法允许对复杂的RE进行分段落和注释。示例6-2:在扩展语法中,RE中的空格被忽略该规则有三个例外:转义字符\后的空白或#被保留示例6-3括号表达式中的空白或#被保留示例6-4空白和注释不能出现多字符符号中。在 ARE 里,方括弧表达式外面,序列(?#ttt) (这里的ttt是任意不包含)的文本)是一个注释,完全被忽略。示例6-5:空格出现在多字符符号中示例6-6:注释出现在多字符符号中当flags中指定了多个有相反含义的选项时,则后出现的选项覆盖前面出现的选项示例7-1:后出现的s选项覆盖了n选项示例7-2:后出现的n选项覆盖了s选项GaussDB(DWS)正则表达式的特殊句法两个特殊的前缀:***: 和***=一个RE可以以两个特殊的前缀中的某一个开头。RE以***:开头RE以***:开头,则剩余的RE被当作一个ARE。(在GaussDB(DWS)中,这通常没有作用,因为RE被假定为ARE;但是,如果正则表达式函数的flags参数指定了ERE或BRE模式,那么它就会起作用。)示例8-1:在BRE匹配模式中(regexp_replace函数的最后一个参数中指定的字母‘b’即表示使用BRE匹配模式),正则表达式中要表示圆括号表达式,需要将圆括号进行转义;同样,表示原子精确次数匹配序列的花括号,也需要进行转义示例8-2:增加***: 前缀后,即使指定了使用BRE匹配模式,也是按照ARE的匹配模式的规则进行匹配RE以***=开头RE以***=开头,则RE的其余部分被认为是一个字面字符串,所有字符都被认为是普通字符。示例9-1:‘|’在ARE匹配模式的正则表达式中是代表或含义的元字符示例9-2:代表或含义的元字符‘|’,在以***=为前缀的正则表达式中,失去其元字符的特殊含义,被看作字符串中的普通字符嵌套选项ARE可以以嵌套选项开头:序列(?xyz) (其中xyz是一个或多个字母字符)指定影响RE其余部分的选项。这些选项覆盖任何先前确定的选项,特别是,它们可以覆盖由正则表达式运算符或正则表达式函数的flags参数隐含的大小写敏感行为。可选择的字母如表2所示中除’g’选项外的其他选项。示例10-1:不含嵌套选项的大小写不敏感匹配示例10-2:嵌套选项中的大小写敏感覆盖flags中的大小写不敏感匹配结语通过上面丰富的示例,深入了解了GaussDB(DWS)正则表达式的特殊句法和flags选项含义,在使用GaussDB(DWS)正则表达式函数时便可以得心应手。原文链接:https://bbs.huaweicloud.com/blogs/242030【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [技术干货] python re模块和正则表达式(下)
    3、数字匹配1、 匹配一段文本中的每行的邮箱http://blog.csdn.net/make164492212/article/details/516566382、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12';分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$3、 匹配qq号。(QQ号从10000开始) [1,9][0,9]{4,}4、 匹配一个浮点数。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d*5、 匹配汉字。 ^[\u4e00-\u9fa5]{0,}$6、 匹配出所有整数4、爬虫123456789101112131415161718192021222324252627282930313233343536373839404142import requests import reimport json def getPage(url):   response=requests.get(url)  return response.text def parsePage(s):     com=re.compile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'          '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>',re.S)   ret=com.finditer(s)  for i in ret:    yield {      "id":i.group("id"),      "title":i.group("title"),      "rating_num":i.group("rating_num"),      "comment_num":i.group("comment_num"),    } def main(num):   url='https://movie.douban.com/top250?start=%s&filter='%num  response_html=getPage(url)  ret=parsePage(response_html)  print(ret)  f=open("move_info7","a",encoding="utf8")   for obj in ret:    print(obj)    data=json.dumps(obj,ensure_ascii=False)    f.write(data+"\n") if __name__ == '__main__':  count=0  for i in range(10):    main(count)    count+=25简化版123456789101112131415161718192021222324252627282930313233343536373839import reimport jsonfrom urllib.request import urlopen def getPage(url):  response = urlopen(url)  return response.read().decode('utf-8') def parsePage(s):  com = re.compile(    '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'    '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)   ret = com.finditer(s)  for i in ret:    yield {      "id": i.group("id"),      "title": i.group("title"),      "rating_num": i.group("rating_num"),      "comment_num": i.group("comment_num"),    }  def main(num):  url = 'https://movie.douban.com/top250?start=%s&filter=' % num  response_html = getPage(url)  ret = parsePage(response_html)  print(ret)  f = open("move_info7", "a", encoding="utf8")   for obj in ret:    print(obj)    data = str(obj)    f.write(data + "\n") count = 0for i in range(10):  main(count)  count += 25flags有很多可选值:re.I(IGNORECASE)忽略大小写,括号内是完整的写法re.M(MULTILINE)多行模式,改变^和$的行为re.S(DOTALL)点可以匹配任意字符,包括换行符re.L(LOCALE)做本地化识别的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境,不推荐使用re.U(UNICODE) 使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flagre.X(VERBOSE)冗长模式,该模式下pattern字符串可以是多行的,忽略空白字符,并可以添加注释实现能计算类似1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式的计算器程序
  • [技术干货] python re模块和正则表达式
    2.4 字符集[][^]正则待匹配字符匹配结果说明小[明李子巧玲珑]*小明和小李子和小巧玲珑小明小李子小巧玲珑表示匹配"小"字后面[明李子巧玲珑]的字符任意次小[^和]*小明和小李子和小巧玲珑小明小李子小巧玲珑表示匹配一个不是"和"的字符任意次[\d]456bdha34563表示匹配任意一个数字,匹配到4个结果[\d]+456bdha34563表示匹配任意个数字,匹配到2个结果2.5 分组 ()与 或 |[^]身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:正则待匹配字符匹配结果说明^[1-9]\d{13,16}[0-9x]$110101198001017032110101198001017032表示可以匹配一个正确的身份证号^[1-9]\d{13,16}[0-9x]$11010119800101701101011980010170表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字^[1-9]\d{14}(\d{2}[0-9x])?$1101011980010170False现在不会匹配错误的身份证号了()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次^([1-9]\d{16}[0-9x]|[1-9]\d{14})$110105199812067023110105199812067023表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14}2.6 转义符 \在正则表达式中,有很多有特殊意义的是元字符,比如\d和\s等,如果要在正则中匹配正常的"\d"而不是"数字"就需要对"\"进行转义,变成'\\'。在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次"\d",字符串中要写成'\\d',那么正则里就要写成"\\\\d",这样就太麻烦了。这个时候我们就用到了r'\d'这个概念,此时的正则是r'\\d'就可以了。正则待匹配字符匹配结果说明\d\dFalse因为在正则表达式中\是有特殊意义的字符,所以要匹配\d本身,用表达式\d无法匹配\\d\dTrue转义\之后变成\\,即可匹配"\\\\d"'\\d'True如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次r'\\d'r'\d'True在字符串之前加r,让整个字符串不转义2.7 贪婪匹配贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配正则待匹配字符匹配结果说明<.*><script>...<script><script>...<script>默认为贪婪匹配模式,会匹配尽量长的字符串<.*?>r'\d'<script><script>加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串几个常用的非贪婪匹配*? 重复任意次,但尽可能少重复+? 重复1次或更多次,但尽可能少重复?? 重复0次或1次,但尽可能少重复{n,m}? 重复n到m次,但尽可能少重复{n,}? 重复n次以上,但尽可能少重复.*?的用法. 是任意字符* 是取 0 至 无限长度? 是非贪婪模式,何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:.*?x 就是取前面任意长度的字符,直到一个x出现三、re模块123456789101112131415161718192021222324252627282930313233import re ret = re.findall('a', 'ea eg an') # 返回所有满足匹配条件的结果,放在列表里print(ret) #结果 : ['a', 'a'] ret = re.search('a', 'va eg an').group()print(ret) #结果 : 'a'# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 ret = re.match('a', 'abc').group() # 同search,不过尽在字符串开始处进行匹配print(ret)#结果 : 'a' ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割print(ret) # ['', '', 'cd'] ret = re.sub('\d', 'H', 'va3eg4an4', 1)#将数字替换成'H',参数1表示只替换1个print(ret) #vaHeg4an4 ret = re.subn('\d', 'H', 'va3eg4an4')#将数字替换成'H',返回元组(替换的结果,替换了多少次)print(ret) obj = re.compile('\d{3}') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串print(ret.group()) #结果 : 123 import reret = re.finditer('\d', 'ds3sy4784a')  #finditer返回一个存放匹配结果的迭代器print(ret) # <callable_iterator object at 0x10195f940>print(next(ret).group()) #查看第一个结果print(next(ret).group()) #查看第二个结果print([i.group() for i in ret]) #查看剩余的左右结果注意:1 findall的优先级查询:1234567import re ret = re.findall('www.(baidu|xunlei).com', 'www.xunlei.com')print(ret) # ['xunlei']   这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall('www.(?:baidu|xunlei).com', 'www.xunlei.com')print(ret) # ['www.xunlei.com']2 split的优先级查询123456789ret=re.split("\d+","va3eg4an")print(ret) #结果 : ['va', 'eg', 'an'] ret=re.split("(\d+)","va3eg4an")print(ret) #结果 : ['va', '3', 'eg', '4', 'an'] #在匹配部分加上()之后所切出的结果是不同的,#没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,#这个在某些需要保留匹配部分的使用过程是非常重要的。3.1 匹配标签12345678910111213import re ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")#还可以在分组中利用?<name>的形式给分组起名字#获取的匹配结果可以直接用group('名字')拿到对应的值print(ret.group('tag_name')) #结果 :h1print(ret.group()) #结果 :<h1>hello</h1> ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")#如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致#获取的匹配结果可以直接用group(序号)拿到对应的值print(ret.group(1))print(ret.group()) #结果 :<h1>hello</h1>2、匹配整数12345678import re ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")print(ret) #['1', '2', '60', '40', '35', '5', '4', '3']ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")print(ret) #['1', '-2', '60', '', '5', '-4', '3']ret.remove("")print(ret) #['1', '-2', '60', '5', '-4', '3']
  • [技术干货] python re模块和正则表达式
    先来看一个例子:https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com/这是京东的注册页面,打开页面我们就看到这些要求输入个人信息的提示。假如我们随意的在手机号码这一栏输入一个11111111111,它会提示我们格式有误。这个功能是怎么实现的呢?假如现在你用python写一段代码,类似:phone_number = input('please input your phone number : ')你怎么判断这个phone_number是合法的呢?根据手机号码一共11位并且是只以13、14、15、18开头的数字这些特点,我们用python写了如下代码:12345678910111213# 方式一 判断号码是否合法# -*- coding:utf-8 -*-while True:  phone_number = str(input('please input your phone number : '))  if len(phone_number) == 11 \      and phone_number.isdigit() \      and (phone_number.startswith('13') \         or phone_number.startswith('14') \         or phone_number.startswith('15') \         or phone_number.startswith('18')):    print('是合法的手机号码')  else:    print('不是合法的手机号码')12345678# 方式二 判断号码是否合法# -*- coding:utf-8 -*-import rephone_number = str(input('please input your phone number : '))if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):    print('是合法的手机号码')else:    print('不是合法的手机号码')正则表达式不仅在python领域,在整个编程届都占有举足轻重的地位。不管以后你是不是去做python开发,只要你是一个程序员就应该了解正则表达式的基本使用。如果未来你要在爬虫领域发展,你就更应该好好学习这方面的知识。但是你要知道,re模块本质上和正则表达式没有关系。re模块和正则表达式的关系 类似于time模块和时间的关系。时间有自己的格式,年月日时分秒,12个月,365天......已经成为了一种规则。正则表达式本身也和python没有什么关系,就是匹配字符串内容的一种规则。官方定义:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。二、正则表达式在线测试工具 http://tool.chinaz.com/regex/首先谈到正则,就只和字符串相关了。在我给你提供的工具中,你输入的每一个字都是一个字符串。其次,如果在一个位置的一个值,不会出现什么变化,那么是不需要规则的。比如你要用"1"去匹配"1",或者用"2"去匹配"2",直接就可以匹配上。这连python的字符串操作都可以轻松做到。那么在之后我们更多要考虑的是在同一个位置上可以出现的字符的范围。2.1 字符组字符组 : [字符组]在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示字符分为很多类,比如数字、字母、标点等等。假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。正则待匹配字符匹配结果说明[0123456789]8True在一个字符组里枚举合法的所有字符,字符组里的任意一个字符和"待匹配字符"相同都视为可以匹配[0123456789]aFalse由于字符组中没有"a"字符,所以不能匹配[0-9]7True也可以用-表示范围,[0-9]就和[0123456789]是一个意思[a-z]sTrue同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示[A-Z]BTrue[A-Z]就表示所有的大写字母[0-9a-fA-F]eTrue可以匹配数字,大小写形式的a~f,用来验证十六进制字符2.2 元字符元字符匹配内容.匹配除换行符以外的任意字符\w匹配字母或数字或下划线\s匹配任意的空白符\d匹配数字\n匹配一个换行符\t匹配一个制表符\b匹配一个单词的结尾^匹配字符串的开始$匹配字符串的结尾\W匹配非字母或数字或下划线\D匹配非数字\S匹配非空白符a|b匹配字符a或字符b()匹配括号内的表达式,也表示一个组[...]匹配字符组中的字符[^...]匹配除了字符组中字符的所有字符2.3 量词量词用法说明*重复零次或更多次+重复一次或更多次?重复零次或一次{n}重复n次{n,}重复n次或更多次{n,m}重复n到m次2.3.1 . ^ $正则待匹配字符匹配结果说明小.小明小军小兰小明小军小兰匹配所有"小."的字符^小.小明小军小兰小明只从开头匹配"小."小.$小明小军小兰小兰只匹配结尾的"小.$"2.3.2 * + ? { }正则待匹配字符匹配结果说明小.?小明和小李子和小巧玲珑小明小李小巧?表示重复零次或一次,即只匹配"小"后面一个任意字符小.*小明和小李子和小巧玲珑小明和小李子和小巧玲珑*表示重复零次或多次,即匹配"小"后面0个或多个任意字符小.+小明和小李子和小巧玲珑小明和小李子和小巧玲珑+表示重复一次或多次,即只匹配"小"后面1个或多个任意字符小.{1,2}小明和小李子和小巧玲珑小明和小李子小巧玲{1,2}匹配1到2次任意字符注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配正则待匹配字符匹配结果说明小.*?小明和小李子和小巧玲珑小小小惰性匹配
  • [技术干货] 【转】linux sed 命令
    sed 是一个流编辑器(stream editor),主要用来执行文本替换。但 sed 的主要设计目的是以批处理的方式而不是交互的方式来编辑文件。命令简介基本命令格式sed [常用选项] 命令文本 输入常用选项    -n (--quiet, --silent):安静模式。在 sed 的基本用法中,所有来自标准输出的信息都会被列出到终端上。加上 -n 参数后,则只有被sed 处理的那些行才会被输出。    -e:指定在指令列模式上执行的命令文本。默认不需要指定,只有同时要执行多个命令文本时才需要显式的指定 -e 选项。    -f:同时要执行多个命令文本时,可以将这些命令文本写到一个文件中,然后通过 -f filename 的方式使用。    -r:sed 默认使用基础正则表达式语法(BRE),指定 -r 选项后使用扩展正则表达式语法(ERE)。    -i:直接修改读取的文档,而不是输出到终端。常用命令    a:新增行, a 的后面接字串,这些字串会被添加到匹配行的下面。    c:替换行, c 的后面接字串,这些字串会替换掉匹配到的行。    d:删除行,删除匹配到的行。    i:插入行, i 的后面接字串,这些字串会**入到匹配行的上面。    p:打印,将某些行输出。通常 p 会与参数  -n 一起使用,这样只输出匹配到的行。    s:字符串替换,主要搭配正则表达式使用。解释一下本文中 "命令" 与 "命令文本" 的区别:命令是一些抽象的操作,比如 a 指示新增行,d 指示删除行。命令文本则是由命令和其它一些信息组合起来的一个字符串,用来执行具体的操作。比如在第一行下面添加一行,内容为 'Hello world',命令文本为:'1a Hello world'再如删除包含字符串 'Hello world' 的行,命令文本为:'/Hello world/d'常用选项及命令详解说明:本文示例中 demo 文件 test.txt 包含三行文字,内容为:aabbccdemo 文件 hello.txt 包含三行文字,内容为:Hello world! Hello Jack!Hello China!Hello Nick!删除行删除行需要使用命令 d:$ sed '1d' test.txt            # 删除第一行$ sed '$d' test.txt            # 删除最后一行$ sed '1,2d' test.txt          # 删除第一行到第二行$ sed '2,$d' test.txt          # 删除第二行到最后一行注意,执行完上面的命令,我们只能在命令行终端上看到正确的结果,而 test.txt 文件根本没有发生变化:选项 -i 如果想要直接在原文件上进行修改(其实是先修改文件的内容,然后保存到原文件中),需要使用选项 -i:$ sed -i '1d' test.txt注意,应用 -i 选项后命令行上没有输出内容,但是源文件被更新了。新增行a 命令可以在匹配的行下面新增行:$ sed '1a Hello world!' test.txt                  # 在第一行下面新增一行,内容为 "Hello world!"$ sed '$a Hello world!' test.txt                  # 在最后一行下面新增一行,内容为 "Hello world!"$ sed '1,3a Hello world!' test.txt                # 在第一行,第二行和第三行下面分别增加一行,内容                                                                    # 为 "Hello world!" 1,3 表示从第一行到第三行$ sed '1a Hello world!\nHello China!' test.txt    # 一次增加多行需要使用换行符 \n选项 -e-e 选项用来指定命令文本,如果只有一个命令文本时 -e 选项可以省略。如何要指定多个命令文本就需要使用 -e 选项。$ sed -e '1a xxx' -e '2a yyy' test.txt插入行i 命令可以在匹配的行上面插入行,语法与新增行相同,只是新行在指定行的上面(与 a 命令的区别):选项 -f前面我们通过选项 -e 添加了多个命令文本,但是如果需要添加比较多的命令文本,使用选项 -e 就不太合适了。因为把所有的命令文本全部写在命令行中会导致维护困难。此时选项 -f 就派上用场了。我们可以把多个命令文本写入到文本文件中,然后通过 -f 选项进行引用。我们创建一个叫 commands 的文件,在里面添加三个命令文本如下:1i Hello world!2i Hello world!3i Hello world!然后执行命令:$ sed -f commands test.txt通过 -f 选项,commands 文件中的三个命令文本都被执行了!替换行使用 c 命令可以轻松的进行整行替换: $ sed '1c  Hello world!' test.txt         # 把第一行替换为 "Hello world!"$ sed '1,3c Hello world!' test.txt        # 把第一行到第三行替换为 "Hello world!"注意,上图中的命令把三行文本替换成了一行文本!字符串替换与行替换不同,s 命令只替换匹配到的内容(一般为字符串):$ sed 's/Hello/Hi/' hello.txt             # 把Hello 替换为 Hi上图带给我们的困惑之一是:为什么第一行中只有第一个 Hello 被替换了?答案是 sed 默认只会替换第一个匹配到的内容!那么我们的第二个困惑来了:如果只替换第一个匹配到的内容,那么为什么第二行和第三行的 Hello 都被替换了呢?这个问题涉及的 sed 的工作方式,sed 是一个以行为单位进行文本处理的工具!所以图中的三行是被分为三次,每次一行进行处理的。因而第二行和第三行中的 Hello 对于本行来说都是第一个匹配到的内容,被替换是正确的。要进行全局替换,需要在命令文本中指定 g,试试下面的命令:$ sed 's/Hello/Hi/g' hello.txt             # 把匹配到的所有Hello 都替换为 Hi这下第一行中的两个 Hello 都被替换了。我们还可以限制执行替换操作的行:$ sed '2,3s/Hello/Hi/g' hello.txt          # 只在第二行和第三行进行替换操作当然也可以通过替换来删除不需要的字符串:$ sed 's/Hello//g' hello.txt               # 删除字符串 Hello定界符虽然 / 是最常用的定界符,但是你也可以使用其它的字符。举个简单的例子,当你要在 linux 下进行路径替换时,使用 / 作为定界符是很不爽的(需要很多的转义符),此时换一个定界符是最好的解决方案:上图中我们使用分号作为定界符轻松实现了路径替换。匹配细心的同学可能已经注意到了,sed 所有的操作都是建立在行定位之上的。也就是说无论你要干什么,都要先找到(匹配)目标行。连最简单的删除行 '1d',也得先定位到第一行,然后才能删除。所以唯一能限制我们发挥 sed 能力的因素就是:如何匹配到期望的行?答案是掌握基本的规则,然后多练习! -n 选项和 p 命令是我们练习的好帮手。-n 选项告诉 sed 只输出那些被处理过的行。比如 sed '1a Hello world!' test.txt 命令默认会输出四行,应用 -n 后只输出一行:p 命令则告诉 sed 只输出那些匹配到的行, 比如命令:$ sed -n '1p' test.txt 和命令sed -n '2,3s/Hello/Hi/gp' hello.txt行匹配的规则大概有两类:通过行号进行匹配和通过正则表达式进行匹配。下面是一些通过行号进行匹配的例子:$ sed -n '1p' test.txt                 # 匹配第一行$ sed -n '$p' test.txt                 # 匹配最后一行$ sed -n '2,3p' test.txt               # 匹配第二行和第三行$ sed -n '3,$p' test.txt               # 匹配第三行和第三行后的每一行下面是通过正则表达式进行匹配的例子:$ sed -n '/Hello/p' hello.txt默认的匹配是区分大小写的,要忽略大小写可以使用I(大写字母i)$ sed -n '/hello/Ip' hello.txt下面几个是正则表达式匹配后执行操作的例子:$ sed '/Hello/d' hello.txt                # 找到匹配的行,并删除$ sed '/Hello/a world!' hello.txt         # 找到匹配的行,并在它们下面添加新行$ sed 's/world/China/g' hello.txt         # 把行中的 world 替换为 China$ sed '/Hello/s/world/China/g' hello.txt  # 找到匹配的行,在这些行中执行替换下面的例子通过正则表达式进行整行内容的替换:$ sed -i 's/^commonName.*/commonName = xxx/g' my.cnf$ sed -i 's/^subjectA**ame.*/subjectA**ame = DNS:xxx/g' my.cnf总结sed 是一个强有力的文本替换工具,尤其是需要在自动化的场景中使用的时候。本文结合实例比较详细的介绍了 sed 的使用方法,希望对大家了解、使用 sed 有所帮助。转自:https://www.cnblogs.com/sparkdev/p/7138073.html
  • [技术干货] SqlServer类似正则表达式的字符处理问题
    SQL Serve提供了简单的字符模糊匹配功能,比如:like, patindex,不过对于某些字符处理场景还显得并不足够,日常碰到的几个问题有:1. 同一个字符/字符串,出现了多少次2. 同一个字符,第N次出现的位置3. 多个相同字符连续,合并为一个字符4. 是否为有效IP/身份证号/手机号等 一. 同一个字符/字符串,出现了多少次同一个字符,将其替换为空串,即可计算declare @text varchar(1000) declare @str varchar(10) set @text = 'ABCBDBE' set @str = 'B' select len(@text) - len(replace(@text,@str,''))同一个字符串,仍然是替换,因为是多个字符,方法1替换后需要做一次除法;方法2替换时增加一个字符,则不需要--方法1 declare @text varchar(1000) declare @str varchar(10) set @text = 'ABBBCBBBDBBBE' set @str = 'BBB' select (len(@text) - len(replace(@text,@str,'')))/len(@str) --方法2 declare @text varchar(1000) declare @str varchar(10) set @text = 'ABBBCBBBDBBBE' set @str = 'BBB' select len(replace(@text,@str,@str+'_')) - len(@text)二. 同一个字符/字符串,第N次出现的位置SQL SERVER定位字符位置的函数为CHARINDEX:CHARINDEX ( expressionToFind , expressionToSearch [ , start_location ] )可以从指定位置起开始检索,但是不能取第N次出现的位置,需要自己写SQL来补充,有以下几种思路:1. 自定义函数, 循环中每次为charindex加一个计数,直到为Nif object_id('NthChar','FN') is not null   drop function Nthchar GO create function NthChar ( @source_string as nvarchar(4000),  @sub_string  as nvarchar(1024), @nth      as int )  returns int as begin   declare @postion int   declare @count  int   set @postion = CHARINDEX(@sub_string, @source_string)    set @count = 0    while @postion > 0    begin     set @count = @count + 1      if @count = @nth      begin       break      end     set @postion = CHARINDEX(@sub_string, @source_string, @postion + 1)    End   return @postion  end GO --select dbo.NthChar('abcabc','abc',2) --42. 通过CTE,对待处理的整个表字段操作, 递归中每次为charindex加一个计数,直到为Nif object_id('tempdb..#T') is not null   drop table #T create table #T ( source_string nvarchar(4000) ) insert into #T values (N'我们我们') insert into #T values (N'我我哦我') declare @sub_string nvarchar(1024) declare @nth    int set @sub_string = N'我们' set @nth = 2 ;with T(source_string, starts, pos, nth)  as (   select source_string, 1, charindex(@sub_string, source_string), 1 from #t   union all   select source_string, pos + 1, charindex(@sub_string, source_string, pos + 1), nth+1 from T   where pos > 0 ) select   source_string, pos, nth from T where pos <> 0  and nth = @nth order by source_string, starts --source_string  pos  nth --我们我们  3  23. 借助数字表 (tally table),到不同起点位置去做charindex,需要先自己构造个数字表--numbers/tally table IF EXISTS (select * from dbo.sysobjects where id = object_id(N'[dbo].[Numbers]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)   DROP TABLE dbo.Numbers --===== Create and populate the Tally table on the fly  SELECT TOP 1000000      IDENTITY(int,1,1) AS number   INTO dbo.Numbers   FROM master.dbo.syscolumns sc1,     master.dbo.syscolumns sc2 --===== Add a Primary Key to maximize performance  ALTER TABLE dbo.Numbers     ADD CONSTRAINT PK_numbers_number PRIMARY KEY CLUSTERED (number) --===== Allow the general public to use it  GRANT SELECT ON dbo.Numbers TO PUBLIC --以上数字表创建一次即可,不需要每次都重复创建 DECLARE @source_string  nvarchar(4000),      @sub_string    nvarchar(1024),      @nth       int SET @source_string = 'abcabcvvvvabc' SET @sub_string = 'abc' SET @nth = 2  ;WITH T  AS (       SELECT ROW_NUMBER() OVER(ORDER BY number) AS nth,     number AS [Position In String]  FROM dbo.Numbers n   WHERE n.number <= LEN(@source_string)     AND CHARINDEX(@sub_string, @source_string, n.number)-number = 0   ----OR   --AND SUBSTRING(@source_string,number,LEN(@sub_string)) = @sub_string )  SELECT * FROM T WHERE nth = @nth4. 通过CROSS APPLY结合charindex,适用于N值较小的时候,因为CROSS APPLY的次数要随着N的变大而增加,语句也要做相应的修改declare @T table ( source_string nvarchar(4000) )   insert into @T values ('abcabc'), ('abcabcvvvvabc') declare @sub_string nvarchar(1024) set @sub_string = 'abc'   select source_string,     p1.pos as no1,     p2.pos as no2,     p3.pos as no3 from @T cross apply (select (charindex(@sub_string, source_string))) as P1(Pos) cross apply (select (charindex(@sub_string, source_string, P1.Pos+1))) as P2(Pos) cross apply (select (charindex(@sub_string, source_string, P2.Pos+1))) as P3(Pos)5. 在SSIS里有内置的函数,但T-SQL中并没有--FINDSTRING in SQL Server 2005 SSIS FINDSTRING([yourColumn], "|", 2), --TOKEN in SQL Server 2012 SSIS TOKEN(Col1,"|",3)注:不难发现,这些方法和字符串拆分的逻辑是类似的,只不过一个是定位,一个是截取,如果要获取第N个字符左右的一个/多个字符,有了N的位置,再结合substring去截取即可;三. 多个相同字符连续,合并为一个字符最常见的就是把多个连续的空格合并为一个空格,解决思路有两个:1. 比较容易想到的就是用多个replace但是究竟需要replace多少次并不确定,所以还得循环多次才行--把两个连续空格替换成一个空格,然后循环,直到charindex检查不到两个连续空格 declare @str varchar(100) set @str='abc    abc   kljlk   kljkl' while(charindex(' ',@str)>0) begin   select @str=replace(@str,' ',' ') end select @str2. 按照空格把字符串拆开对每一段拆分开的字符串trim或者replace后,再用一个空格连接,有点繁琐,没写代码示例,如何拆分字符串可参考:“第N次出现的位置”;四. 是否为有效IP/身份证号/手机号等类似IP/身份证号/手机号等这些字符串,往往都有自身特定的规律,通过substring去逐位或逐段判断是可以的,但SQL语句的方式往往性能不佳,建议尝试正则函数,见下。五. 正则表达式函数1. Oracle从10g开始,可以在查询中使用正则表达式,它通过一些支持正则表达式的函数来实现:Oracle 10 g REGEXP_LIKE REGEXP_REPLACE REGEXP_INSTR REGEXP_SUBSTR Oracle 11g (新增) REGEXP_COUNTOracle用REGEXP函数处理上面几个问题:(1) 同一个字符/字符串,出现了多少次select length(regexp_replace('123-345-566', '[^-]', '')) from dual; select REGEXP_COUNT('123-345-566', '-') from dual; --Oracle 11g(2) 同一个字符/字符串,第N次出现的位置不需要正则,ORACLE的instr可以直接查找位置:instr('source_string','sub_string' [,n][,m])n表示从第n个字符开始搜索,缺省值为1,m表示第m次出现,缺省值为1select instr('abcdefghijkabc','abc', 1, 2) position from dual;(3) 多个相同字符连续,合并为一个字符select regexp_replace(trim('agc f  f '),'\s+',' ') from dual;(4) 是否为有效IP/身份证号/手机号等--是否为有效IP WITH IP AS( SELECT '10.20.30.40' ip_address FROM dual UNION ALL SELECT 'a.b.c.d' ip_address FROM dual UNION ALL SELECT '256.123.0.254' ip_address FROM dual UNION ALL SELECT '255.255.255.255' ip_address FROM dual ) SELECT * FROM IP WHERE REGEXP_LIKE(ip_address, '^(([0-9]{1}|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]{1}|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'); --是否为有效身份证/手机号,暂未举例
  • [技术干货] 【转载】JavaScript中的正则表达式详解
    摘要:javascript中的正则表达式作为相当重要的知识,本文将介绍正则表达式的相关知识和用法。正则表达式(Regular Expression)是一门简单语言的语法规范,是强大、便捷、高效的文本处理工具,它应用在一些方法中,对字符串中的信息实现查找、替换和提取操作。正则表达式在人们的印象中可能是一堆无法理解的字符,但就是这些符号却实现了字符串的高效操作。javascript中的正则表达式作为相当重要的知识,本文将介绍正则表达式的相关知识和用法。正则表达式的概念:官方:正则表达式(regular expression)是一个描述字符模式的对象。 ECMAScript 的RegExp类表示正则表达式,而String和正则表达式都定义了进行强大的【模式匹配】和【文本检索】与【替换】的函数。本人理解:功能和字符串类似,但是比字符串强大,更像是服务字符串的,例如表单验证创建正则表达式:1.通过new关键字声明var reg=new RegExp("hello","ig")【注】 第一个参数为正则表达式的主体,是字符串型,第二个参数为修饰符 i 和 gi的作用是忽略大小写,g的作用是全局匹配,在书写的时候,它们两个前后顺序没有区别。2.省略new关键字声明var reg=new RegExp("hello","ig");3.通过正则表达式的声明规则直接赋值var reg=/hello/ig;正则表达式的方法:正则表达式对象只有两个方法text方法: 正则表达式.text(字符串) 在字符串中匹配这个正则表达式是否存在如果匹配成功返回true,匹配失败返回false。exec方法:正则表达式.exec(字符串) 在字符串中匹配这个正则表达式是否存在,匹配成功,返回一个装有字符串的数组,匹配失败返回null正则表达式的更多功能体现在元字符元字符的概念:在正则表达式中有特殊含义的字符【注】 . 匹配单个的任意字符; []匹配单个在范围内的字符;[^] 匹配单个不在范围内的字符。【注】x{n} 必须匹配n个x【注】只需要了解前两个,^ 行首匹配 必须以这个正则开头$ 行尾匹配 必须以这个正则结尾以上常见的元字符,我从别的地方获取的表格资源,但是最重要的还是练习!!下面让我们一起简单练习几个常见的吧!var str="google"; var reg=/google/; reg.text(str); //true用 . 的 形式var str="goggle"; var reg=/go.gle/; reg.text(str);//true .对应的单个字符为任意用[] 的形式var str="go2gle"; var reg=/go[0-9]gle/; reg.text(str);//true []对应的字符必须符合[]中的范围,否则为false用x? 的形式var str="gogle"; var str1="google"; var reg=/goo?gle/; reg.text(str);//true reg.text(str1);//true 0? 代表可以有0个O或者1个O,用 x+ 的形式var str="google"; var str1="googe";ar reg=/googl+e/; reg.text(str);//true reg.text(str1);//false l+ 代表至少存在一个l用 ^ 的形式var str="I am Li"; var str1="you are Li"; ar reg=/^you/; reg.text(str);//false reg.text(str1)//true 字符串必须以you开头精力有限,希望大家下去后,把所以元字符练习一遍,加深印象。前面说到正则表达式是方便字符串的,那么我们今天在这里也简单罗列一下字符串中用到正则表达式的方法在字符串中使用正则表达式的方法:match() : 字符串.match(正则表达式) 在字符串中匹配,是否有符合正则表达式,匹配成功,返回一个装有子串的数组,匹配失败,返回nullreplace() : 字符串.replace(oldStr,newStr) 用newStr将oldStr替换,返回替换成功的新字符串【注】乍一看和正则没有关系,但是oldStr可以用正则表达式的形式。split() : 字符串.split(分隔符) 用分隔符将原字符串进行分割,返回剩下的子串组成的数组。【注】分隔符一般为字符串,也可以为正则表达式。search(): 字符串.search(子串) 找到复合条件的子串第一次出现的位置,如果找到,返回第一次出现子串的位置,并且为子串的首元素位置,否则返回-1。
总条数:51 到第
上滑加载中