正则表达式基础、原理及优化

前言

  正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。简单说就是一个特殊的字符串去匹配一个字符串。定义了一些规则,用于匹配满足这些规则的字符串。

  对于正则表达式应该很多人第一感觉就是很难,完全没有规律,看不懂。
  我觉得可能有以下几个原因:
  1、读不懂。
    各种不同的字符组合一起,难以理解。确实,对于熟悉正则表达式的人来说,一个稍微长点的正则表达式想要理解起来,可能也要花费一定的功夫。可读性差是正则表达式的一个很大的缺点。
    如:[\w!#$%&‘*+/=?^_`{|}~-]+(?:\.[\w!#$%&‘*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?
  2、写不出来
    各种标点符合,完全不知道什么意思,没法写。
  3、很多工具,很多编程语言都有正则表达式,而往往这些正则表达式存在细微的差别。
  4、写出来的正则表达式有问题,匹配了非期望的字符串,甚至把期望的字符串给遗漏了。

  另外通常情况下正则的速度确实相对慢一些。但是很多情况下正则表达式太慢是由于写的正则表达式有问题,没有优化。我并不推荐大量使用正则表达式,有些情况下又非用不可。(想检测一个字符串中是否含有the, \bthe\b)

  关于匹配

  本教程所说的匹配成功,并不是指正则表达式完全匹配目标字符串,指正则表达式能匹配目标字符串的部分。无特殊说明,仅匹配一次

推荐的书籍和网站:

  精通正则表达式(第三版)
  http://rubular.com/ 测试正则表达式

基本概念

  如果想找出当前目录所有的.txt文件。用过windows或者linux命令行的应该知道使用“dir *.txt 、ls*.txt”去查找。为什么这个字符串能找到所有的txt文件呢?因为*这个字符有特殊的含义,表示任意文本。那么.txt有什么特殊含义呢?没有什么含义,就是表示他们自身。所有*.txt表示任意文本开通,但是以.txt结尾就行。

  正则表达式有两种字符组成(是不是很简单),如上面例子中的*,属于特殊字符,也称之为元字符,表示的不是字面上的含义;还有一种就是上面说的.txt,表示普通文本字符。
  正则表达式之所以强大,靠的就是元字符提供了强大的描述能力。下面介绍一些常用的元字符。

1、行的起始^和结束$(字符串的起始和结束)

  ^表示一行的起始,$表示一行的结束。这是最简单的两个元字符了。
  例如cat可以匹配所有cat单词,以及包含cat字符的单词。^cat只能找到行首的cat,同样cat$表示行尾的cat。简单来说^和$匹配的是一个位置,并不匹配任何字符。元字符不仅可以匹配字符,还可以匹配特定位置。

  关于正则表达式的理解

  1、^cat匹配以cat开头的行
  2、^cat匹配的是以c作为一行的第一个字符,紧接着一个a,接着一个t的文本
  这两种结果并没有什么差异,但是第二种更符合正则表达式的逻辑,对后面分析会有帮助。
  ^cat$ 匹配的是行开头,然后是一个c,接着一个a,接着一个t,然后是行尾。
  ^$ 行开头,然后行结尾(空行)
  ^ 行开头 (没有特殊意义,每行都有开头,当然可以用来统计行数)
  注意,对于一个字符串来说,如java或者python中^和$表示字符串的起始和结束,如^cat$不能匹配"cat\ncat"

2、字符组[]

  比如我们搜索单词grey(灰色),但是也有可能写作gray。我们怎么用正则表达式同时能匹配上grey和gray呢?
  这时可以考虑使用字符组[],用中括号将某处期望出现的字符括起来。[ea]表示匹配e或者a,gr[ea]p的意思是:先找到g,跟着一个r,然后是一个a或者e,最后是一个y。
  可以看出在字符组外,普通字符都是(接下来是)的意思,首先匹配g,接下来是r等等。但是在字符组内是完全不一样的,表示的意思是或,就是指必须匹配字符组中的一个字符,仅只能匹配其中一个。如这个表达式并不能匹配greay
  <H[123456]>可以用来匹配<H1>、<H2>等一直到<H6>,注意<>并不是元字符。

  字符组元字符

  连字符-
  上面的<H[123456]>可以写成<H[1-6]>,是等效的。-连字符表示一个范围,表示字符组内的字符是1到6,包括1和6(和通常编程里面的范围不太一样)。就是指这个字符在字符组内才是元字符,否则就是普通字符或者其他意义的元字符。同样的,反过来,字符组外的元字符在字符组内就不是元字符了,或者是不同意义的元字符。
  [0-9A-Za-z]  支持多重范围,表示可以匹配0-9,A-Z,a-z中的任意一个字符
  [0-9a-zA-Z]  顺序也可以颠倒(0-9不能颠倒)
  [0-9a-zA-Z_!.?]   可以和普通文本结合起来。
  注意:-连号只有出现在字符组中字符中间才算连字符,出现在开头就不算了。(出现在结尾呢?当然也不是字符组元字符了)

  排除型字符  [^...]

  [^...],字符组中的^如果出现在第一个位置,也是一个字符组元字符。匹配的是所有没有被字符组列出来的任何字符。简单说就是表示排除的意思,不希望匹配的字符。
  例如:例如英文单词中,q后面通常跟的是字母是u,很奇怪,我想找出q后面不是u的单词怎么办? q[^u].表示的就是匹配的是一个,q然后一个非u的字符。我们发现q和Iraq没有被匹配上。
  注意:匹配一个没有列出的字符,而不是不要匹配列出的字符。看起来差不多,但是有些细微差别。重点在于q后面需要匹配一个字符,排除型字符组也需要匹配一个字符。

3、用点号匹配任意字符

  例如:对于这三个日期,2017-07-12、2017.07.12、2017/07/12,利用上面学过的元字符,可以表示为:2017[-./]07[-./]12。注意:虽然可以匹配上面的三个字符串,但也会匹配一些非法的日期如2017/07.12等。
  注意:编写正则表达式一定要和实际应用环境结合起来。比如只是想相对精确的找出2017-07-12这个日期,那么用这个表达式就可以了。如果你的应用中只接受上面三种格式,其他格式都是错误的,你需要精确的匹配日期。那么上面的正则表达式就不能满足要求了。第一种,只是相对精确的匹配目标字符串,只要目标字符串使我们想要的,那么一定匹配到,可以容许少量的非法字符串。第二种就是精确匹配期望的字符串,不要匹配不期望的字符串。理想情况下正则表达式都是第二种,但是这种正则表达式会更难写一点,有时候也不一定能写出来。需要在复杂性和完整性之前取得平衡。
  再稍微不精确一点,可以使用2017.07.12来进行匹配。这里的.点号就不是字面上的意思了,它是一个元字符,表示匹配任意单个字符(通常不匹配换行符\n)

4、多选结构 |

  多选结构是用来匹配任意子表达式,用这个符号“|”表示,是或的意思。它可以把不同的子表达式组合成一个总的表达式,而这个总的表达式可以匹配任意的子表达式。如上面的日期的例子:如果想精确匹配,正则表达式可以这么写2017-07-12|2017\.07\.12|2017/07/12。它是把三个子表达式组合起来了,可以匹配任意一个表达式。注意.之前有反斜杠,因为.号是元字符,反斜杠可以把元字符变成原始的含义。
  这个和字符组是类似的,都是表示或的意思,字符组只能选择单个字符,多选结构可以选择一个字符串。gr[ea]y也可以用多选结构来写,grey|gray。还可以简写成gr(e|a)y。可以用括号来限定多选的范围,括号也是元字符。
  注意:多选结构与其他元字符一起使用,一定要注意他的使用范围。必要时用括号括起来。
  ^From|Subject|Date:,我们可能期望的是行起始跟着From或者Subject或者Date,然后后面接着一个:。^(From|Subject|Date):才能完全匹配我们的期望字符串。

5、单词分界符 \b

  b本身不是元字符,但是通过反斜杠转义后变成了元字符。表示的是一个单词的分界符。它匹配的也是一个位置。\bcat\b就能匹配It is a cat.中cat单词了,cats之列的就匹配不上。\ba通常用来表示a的前面不是字母和数字。

6、可选项元素 ?

  对于colour(颜色, 英式),同样存在color(美式)。我们需要匹配这两种格式。我们使用了colo(r|ur),但是我们还可以更简单点。
  colou?r可以解决这个问题。?表示的意思就是可选项,它加在一个字符后面,表示他允许出现这个字符,当然也可以不出现。简单来说就是匹配0个或者1个字符,优先匹配1个字符。如果它不是跟着字符后面,可能表示其他含义。
  它只作用于紧邻的字符。上述正则表达式的意思是匹配一个 c,然后是o,然后是l,然后是o,然后是u?,然后是r。其中u?总是可以匹配成功的,如果出现u,就匹配u,如果没有,就什么都不匹配。也就是说,不管u存不存在,u?都是匹配成功的。例如对于这个例子,semicolon,首先是一个c,接着一个o,接着一个l,接着一个u?,虽然单词这里没有u,u?也是匹配成功的。到目前为止colou?已经匹配了colo这四个字符了,接着后面跟着一个r,但是r不能匹配n,所以最终匹配失败了。

  字符串July 4th和July 4可以用这个正则July 4(th)?来匹配,括号可以限定?的作用范围,其实括号的一个主要作用就是限制所以范围。

7、其他量词*  + 区间{min,max}

  加好+ ,星号 * 和?很类似。并不单独使用,而是作用在其他字符后面,限定个数使用。
  * 出现0次或更多次。下限0次,无上限。含义是匹配尽可能多的次数,如果实在无法匹配,那也没有关系。
  + 出现1次或更多次。下限1次,无上限。匹配尽可能多的次数,但如果一次都匹配不了,那么久匹配失败。

  例如:a* a? a+分别匹配下面这三个字符串

  aaaab:a*匹配了aaaa;a?匹配了a;a+匹配了aaaa。(a?只匹配第一个a,因为我们这里讨论的是匹配一次就结束匹配。)

  ab: a*匹配了a;a?匹配了a;a+匹配了a。

  b:a*选择匹配0个字符串,匹配成功了。a?同样选择匹配0个字符,也匹配成功了;a+只要需要匹配一个a,这里没有a,所以匹配失败了。

  注意 :*和?一样是永远不会匹配失败的,只是匹配的内容不一样。
  ? * +可以统称为量词,他们的作用是限定所所用元素的匹配次数。量词是贪婪的,他会匹配尽可能多的字符,直到无法匹配。

  规定出现的次数的范围:区间{min,max}
  {min,max},至少出现min次,最多出现max次。

  {min, }  max可以省略,表示最少出现minci,无上限。

  {num}  正好出现num次。
  例如:  a{1,5},a至少出现1次,最多出现5次。

  注意:量词和区间范围都是匹配优先的。

8、环视(又称 零宽断言)

  (?=...) 顺序环视,表示的含义是,从左到右顺序查看文本,如果能够匹配就返回匹配成功。

  如a(?=def),表示的含义,首先有一个a,接着一个d,接着一个e,接着一个f,如果成功,则返回成功。匹配adef就可能成功。
  顺序环视匹配的也是一个位置,并不占用字符
  (?=Jeffrey) 去匹配Jeffrey Fried。匹配的就是J前面的位置
  (?=Jeffrey)Jeff可以获得更精确的结果。
  同样还有逆序环视
  (?<=...),表示从右到左环视字符串。(?<=Jeffrey)匹配的是y后面的位置。
  上面又称肯定环视
  将等号换成!就表示否定环视
  如(?!...) 顺序否定环视
  (?<!...)逆序否定环视
  re.split(r‘(?<=a)b(?=c)‘, ‘123b321abc123‘)   [‘123b321a‘, ‘c123‘]

  re.split(r‘(?<!a)b(?!c)‘, ‘123b321abc123‘)     [‘123‘, ‘321abc123‘]

  注意:环视的限制,环视中可以出现什么表达式通常有限制,一般顺序环视没有限制,逆序环视往往限制匹配的长度。(?<=books?)往往是不合法的正则表达式,因为匹配文本长度是不确定的。

括号的作用

  1、限制作用域

  如前面限制|  ?  {min, max}  + *等作用域

  2、捕获期望字符串。可以进行分组和反向引用。可以有多个括号,捕获的顺序是(出现的次序。括号能够记住自己匹配上的内容,这样可以进场分组和反向引用。
    2.1、分组,大部分语言都提供分组的功能。如python中:

  

import re
#2017.07.12
re.match(r‘([0-9]{4}).([0-9]{2}).[0-9]{2}‘, ‘2017-07-12‘).group(1)

    2.2、反向引用,反斜杠加上数字,表示当前位置匹配第几个分组中的内容。从1开始
    例如:

    ([a-z])([1-9])\2\1,其中\1匹配的是[a-z]匹配的内容,\2匹配的是[1-9]匹配的内容。能够匹配a11a等对称的字符串。
    (([a-z])([1-9]))\3\2去匹配a11a,第一个括号捕获的是a11a,第二个括号匹配的是a,第三个是1

    还是之前日期的例子,正则表达式2017([-./])07(\1)12,可以精确匹配这三个‘2017-07-12‘, ‘2017.07.12‘, ‘2017/07/12‘中的一个,不会匹配其他字符串。注意\1加了括号,因为1后面还有数字,避免  混淆。同时加了括号,那么又会多出一个捕获分组。

  3、组合成其他元字符

  例如环视

  4、命名捕获

  (P?<Name>...)

  python中:

print re.match(r‘(?P<word>\w+)(?P=word)‘, ‘pythonpython‘).group(‘word‘)

  java中:

Pattern pattern = Pattern.compile("(?<word>\\w+)\\k<word>");
Matcher matcher = pattern.matcher("javajava");
if(matcher.matches()){
    System.out.println(matcher.group("word"));
}

  注意:一个字符是否是元字符,取决于所属环境,如在字符组内.号就不是字符组。部分元字符加上反斜杠转义成普通字符,部分普通字符加上反斜杠变成元字符。

其他常用元字符

  \t制表符,tap
  \n换行符
  \s 任何空白字符(包括制表符,换行,空格等)常用
  \S除了\s以外的字符
  \w [a-zA-Z0-9],通常用\w+匹配单词,注意的是部分工具中\w可以匹配unicode中的“字母”如汉字,notepad++
  \d [0-9]
  \D 除了\d意外的字符,[^0-9]

  大多数正则表达式都提供对unicode的支持。
  \u4e2d匹配中文的中字。
  [\u4e00-\u9fa5]可以用这个来表示中文字符。

  忽略优先量词 *? +? {m,n}?,前面提到的匹配优先量词加上?,就变成忽略优先量词,优先匹配下限次数。如a+?去匹配aaaab,只会匹配第一个a。

  占有优先量词 *+  ?+  ++  {m,n}+,匹配优先量词加上+,不会交还已匹配的字符。目前主要是java.util.regex这个包提供这个功能。\d+0 匹配123450是可以匹配成功的。但是\d++0是无法匹配成功的。

匹配原理

  正则匹配引擎主要分为两类,DFA和NFA,发展的过程也产生了一些变体

  DFA引擎  主要有awk MySQL

  传统型NFA引擎  主要有python java PHP Ruby sed .NET

  其他引擎等

  DFA不支持忽略优先量词,基本上就是传统型NFA。本教程只关注传统型NFA引擎的正则表达式。

  有两条普遍的规则,适用于大多数NFA和DFA引擎。

规则一 优先选择最左端的匹配结果

  起始位置最靠左的匹配结果总是优先其他可能的结果。匹配先从需要查找的字符串的起始位置尝试匹配。尝试匹配的意思是,在当前位置测试整个表达式能匹配的文本。如果当前位置测试了所有可能之后不能找到匹配结果,那么就会从第二个字符之前的位置开始重新尝试匹配。在找到匹配前会一直重复这个过程,如果尝试了所有位置,都找不到匹配结果的情况下,才会报告匹配失败。

例如:使用ORA来匹配FLORAL,首先第一轮从F前面开始匹配,用O去尝试匹配,尝试会失败;然后从F后面L前面开始匹配,仍然用O去尝试匹配,失败;第三次尝试成功。

规则二 标准量词是匹配优先的* ? + {m,n}

  标准量词并非是所有可能中最长的,但它们匹配尽可能多的字符,直到上限。\b\w+s\b来匹配结尾是s的单词。比如匹配regexes,\w+是可以匹配整个单词的,但是如果\w+匹配了整个单词,s\b就无法匹配了,所有\w+只能匹配regexe,最后的字符让s\b去匹配

  ^Subject:(.*),如果^Subject:部分匹配成功了,那么整个正则表达式都会匹配成功。.*的目的是*是匹配优先的,会把剩下的所有字符都匹配上。这是我们期望的。

过度的优先匹配

  ^.*\d\d能够匹配一行中最后的两个数字。对于这个字符串,about 24 characters long,首先.*匹配了整个字符串,这时候第一个\d需要匹配,为了避免匹配失败,.*需要交出最后一个字符g,显然\d无法匹配g,.*继续交出下一个字符n,这样循环15次,最终交出4时候,\d终于可以匹配上了,但是第二个\d仍然无法匹配,所以.*必须再交出一个字符2。这样.*匹配了“about ”,\d\d匹配了24。

NFA引擎:表达式主导

  例如:to(nite|knight|night) 去匹配‘...tonight...‘。正则表达式第一个需要匹配的是t,它去字符串中寻找t,从第一个位置开始寻找,找到后停下,接下来是o,检查o能否匹配下一个字符,如果能匹配,继续检查下面的元素。下面的元素指的是(nite|knight|night)它们是或的关系。引擎会尝试这三种可能。在尝试nite的过程和之前一样,尝试匹配n,接着是i,最后是e。

  NFA具有表达式主导的特性,引擎的匹配原理就很重要,如果我们改变表达式,可以节省很多时间。
  to(ni(ght|te)|knight)
  tonite|toknight|tonight
  to(k?night|nite)

回溯

  NFA最重要的性质是,它会一次处理各个子表达式或组成的元素,遇到需要在两个可能的成功的可能中进行选择的时候,它会选择其一,同时记住另一个,以备稍后可能的需要。

  需要作出选择的情形主要包括量词和多选结构。无论选择哪一个途径,如果匹配成功了,其余下的也匹配成功了,那么匹配就结束了,如果余下的匹配失败了,引擎会回溯到之前做出选择的地方,选择其他的备用分支继续尝试。这样,引擎会尝试表达式的所有可能途径,直到匹配成功,或者尝试完所有路径并失败。

  例如:对于to(nite|knight|night)去匹配hot tonic tonight

  首先用正则表达式的t,从字符串的起始位置开始匹配,首先t无法匹配h,第一轮匹配失败,第二轮,t匹配o,同样失败,第三轮,t匹配成功,但是接下来o不匹配空格,导致本轮失败。进行第四轮匹配,to匹配成功,进入3个多选分支。三个分支都有可能。假设选择的是nite进行匹配,首先是n匹配成功,接着是i匹配成功,但是到c的时候匹配失败。这个失败并不会导致这一轮失败,也就是这个位置的匹配失败,因为还有其他分支没有尝试。假设接下来尝试knight,这时候回溯到to和nic之间的位置,显然第一次匹配,k与n匹配失败,那么只剩下night继续匹配了,显然这一次也失败了,这导致这个位置的匹配全部失败。这样会进入下一个位置,重复上面的操作。最终到tonight的前的位置时,选择night这个分支匹配成功了。

回溯的两个要点。

  在匹配时,当出现多个选择时,应该首先选择哪个?
    1、对于匹配优先量词,会优先进行匹配。
    2、对于忽略优先量词,会选择跳过尝试。
    3、对于多选结构,会选择按顺序进行尝试。
  当需要回溯时,应该选择哪个备用状态。
    选择当前最近存储的选项。如果前面是死路,你只需要沿路返回,找到上一次做出选择的地方。

关于备用状态

  ab?c 匹配 abc   首先a匹配a,成功,接着b?去匹配b,这时候有可能失败,所以必须记下备用状态ab? · c和a · bc,b?匹配b成功,接着c匹配c成功。最终匹配成功,备用状态也丢弃了。
  ab?c 匹配 ac     首先a匹配a,成功,接着b?去匹配c,这时候有可能失败,所以必须记下备用状态ab? · c和a · c,b?匹配c失败,选用回溯到备用状态,接着c匹配c成功。最终匹配成功,备用状态也丢弃了。

  ab?c 匹配 abx   首先a匹配a,成功,接着b?去匹配b,这时候有可能失败,所以必须记下备用状态ab?·c和a·bx,b?匹配b成功,接着c匹配x失败,选用回溯到备用状态,接着c匹配b失败。但是整个匹配还没有结束。还会继续匹配下去。

  *和+的回溯
  \d+ 去匹配 a 1234 num,在用\d去匹配空格的时候,失败了,那么它会回溯。
  a 1`234 num
  a 12`34 num
  a 123`4 num
  a 1234` num
  \d+`去匹配空格,但是此时表达式已经匹配完成,并且已经匹配到数据了,那么整个匹配结束。
  a `1234 num这个位置并不在备用选项中,\d*来匹配整个字符串,会有这个备用选项吗?

一些问题
  .*的问题 ".*"去匹配双引号文本
  <input name="id" value="1">,结果发现匹配的是"id" value="1"这个文本,"[^"]*"就可以了。

  <B>name</B>and<B>age</B> 使用<B>.*</B>去匹配,同样出现上面的问题,但是我们不能使用<B>[^</B>]*</B>。
  <B>.*?</B>    使用忽略优先量词

  占有优先量词,java中提供了占有优先量词,它不会交回已匹配的字符,可以避免备用状态。
  \d++元 去匹配金额,1231231美元。
  \d++\d永远无法匹配任何字符。

多选结构的陷阱
  Jan 1到 Jan 31,需要匹配合法的日期
  Jan [0-3][0-9] 无法匹配Jan 1 却能匹配Jan 00
  Jan (0?[1-9]|[12][0-9]|3[01])看起来没有任何问题。可以匹配Jan 2,Jan 01,但是匹配Jan 21的时候匹配的是Jan 2。
  Jan ([12][0-9]|3[01]|0?[1-9])

正则表达式的实用技巧

  理想情况中,好的正则表达式必须在下面这些方面取得平衡。

    1、只匹配期望的文本,排除不期望的文本

    2、易于控制和理解

    3、必须保证效率(如果能够匹配,必须很快返回结果,如果不能匹配,应该尽可能快的报告匹配失败)

  现实情况,好的正则表达式与具体问题结合。在完整性和复杂性之间取得平衡。

  避免优化过度

  为提高效率而改动正则表达式最需要考虑的问题是,改动是否会影响准确性。

  必要时才进行优化,优化需要考虑使用的环境和语言,优化后需要测试

正则表达式的匹配过程

  正则表达式编译,检测语法,编译成内部形式

  开始匹配,定位到字符串的起始位置

  元素检测 依次测试正则表达式的各个元素。

  相连元素会依次尝试 Subject

  量词修饰的元素,控制权会在量词和被限定的匀速直接轮换

  控制权在捕获型括号内外切换回带来一些开销。

  寻找匹配结果 如果遭到匹配结果,就会报告匹配成功。

  继续匹配 如果没有找到匹配,就会从下一个字符继续匹配。

  匹配彻底失败,所有尝试都失败了,就会报告匹配失败

简单优化措施

  1、消除不必要的括号,必须使用括号时,请尽量使用非捕获型括号

    例如:.* 和 (?:.)*

  2、消除不必要的字符组

    例如:[.] 和 \.

  3、使用.*开头的表达式应该在最前面加^

    例如:.*abc  vs  ^.*abc

  4、在多选结构中提取开头的必需元素

    例如:th(?:is|at) 替代 (?:this|that)

  5、多选结构的代价

    例如:u|v|w|x|y|z  VS [uvwxyz],尽量避免多选结构

  6、改变多选结构的顺序

    例如:去匹配引号中的字符,并且能够匹配转义的引号。"(\\.|[^"\\])*"去匹配"2\"x3\" likeness" 。可以优化"([^"\\]|\\.)*"

时间: 2024-10-13 11:40:44

正则表达式基础、原理及优化的相关文章

正则表达式基础、原理

正则表达式(regular expression)是一个特殊的字符序列,描述了一种字符串匹配的模式,可以用来检查一个字符串是否含有某种子字符串. 将匹配的子字符串替换或者从某个字符串中取出符合某个条件的子字符串,或者是在指定的文章中抓取特定的字符串等. Python处理正则表达式的模块是re模块,它是Python语言中拥有全部的正则表达式功能的模块. 正则表达式由一些普通字符和一些元字符组成.普通字符包括大小写的字母.数字和打印符号,而元字符是具有特殊含义的字符. 正则表达式大致的匹配过程是:

前端学PHP之正则表达式基础语法

前面的话 正则表达式是用于描述字符排列和匹配模式的一种语法规则.它主要用于字符串的模式分割.匹配.查找及替换操作.在PHP中,正则表达式一般是由正规字符和一些特殊字符(类似于通配符)联合构成的一个文本模式的程序性描述.正则表达式有三个作用:1.匹配,也常常用于从字符串中析取信息:2.用新文本代替匹配文本:3.将一个字符串拆分为一组更小的信息块.本文将详细介绍PHP中的正则表达式基础语法 [注意]关于javascript的正则表达式的详细信息移步至此 历史 在PHP中有两套正则表达式函数库,两者功

刨根究底正则表达式之二——正则表达式基础

正则表达式基础 一.正则表达式构成 1. 正则表达式中的语法元素,从是否具有特殊含义的角度进行分类,可分为下列两大类.共五种语法元素: 1)不具有特殊含义的语法元素 (1)  字面字符(文本字符):不具有特殊含义的单个字符,代表字符自身(即字符字面值): (2)  普通转义序列:由转义前导符\后跟元字符所组成的字符序列,将具有特殊含义的元字符,转义为(即转换为)不具有特殊含义的字符本身(即字符字面值): 2)具有特殊含义的语法元素 (1)  元字符:具有特殊含义的单个字符,包括:\.(.).[.

Web Service 之 http基础原理

Web Service 之 http基础原理 ========================================================================= 概述: 网络通信基础 ★进程间通信:IPC Socket(套接字):ip:port ★Client <--> Server Server: listen(监听状态,表示服务器正在等待新的传输链接进入) Client: ★客户端与服务器间通信实际上是客户端套接字和服务器端套接字间通信 IP:PORT(Cl

Nginx工作原理和优化

Nginx工作原理和优化 分类: Linux webserver2013-05-16 11:04 4975人阅读 评论(0) 收藏 举报 目录(?)[+] 1.  Nginx的模块与工作原理 Nginx由内核和模块组成,其中,内核的设计非常微小和简洁,完成的工作也非常简单,仅仅通过查找配置文件将客户端请求映射到一个location block(location是Nginx配置中的一个指令,用于URL匹配),而在这个location中所配置的每个指令将会启动不同的模块去完成相应的工作. Nginx

MySQL join的实现原理及优化思路

Join 的实现原理 在MySQL 中,只有一种Join 算法,也就是Nested Loop Join,没有其他很多数据库所提供的Hash Join,也没有Sort Merge Join.顾名思义,Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果.如果还有第三个参与Join,则再通过前两个表的Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复. 下面

浏览器内核、引擎、页面呈现原理及其优化

浏览器内核.引擎.页面呈现原理及其优化 介绍浏览器内核.JavaScript 引擎以及页面呈现原理等基础知识,同时根据原理提出页面呈现优化方案. 浏览器内核 浏览器内核又叫渲染引擎,主要负责 HTML.CSS 的解析,页面布局.渲染与复合层合成.浏览器内核的不同带来的主要问题是对 CSS 的支持度与属性表现差异. 现在主流的内核有:Blink.Webkit.Gecko.EdgeHTML.Trident,这里面有几个需要注意的地方: Blink 是在 Webkit 的基础上的改进,是现在对新特性支

mysql索引查找原理及优化

原文:mysql索引查找原理及优化 常见查找方法 1.顺序查找(linear search ) 1. 最基本的查询算法当然是顺序查找(linear search),也就是对比每个元素的方法,不过这种算法在数据量很大时效率是极低的. 2. 数据结构:有序或无序队列 3. 复杂度:O(n) 2.二分查找 1. 从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束: 2. 如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且根开始一样从中间元素开始比较.

Linux高可用集群方案之heartbeat基础原理及逻辑架构

 这篇文章我们主要学习heartbeat高可用集群的基础原理及逻辑架构,以及heartbeat的简单配置  ll  本文导航    · heartbeat之基本原理   · heartbeat之集群组件   · heartbeat之心跳连接   · heartbeat之脑裂(资源争用.资源隔离) · heartbeat之配置文件   · heartbeat至高可用集群配置  ll  要求  掌握heartbeat高可用集群的相关组件及简单配置   heartbeat之基本原理  heartbea

49 Linux操作系统原理、虚拟化技术基础原理

04 虚拟化技术基础原理 一.配置虚拟化网络 1.编辑配置文件 #关闭NetworkManager [[email protected] ~]# service NetworkManager stop [[email protected] ~]# chkconfig NetworkManager off    [[email protected] ~]# chkconfig --list NetworkManager NetworkManager  0:关闭  1:关闭  2:关闭  3:关闭