多数大学生出来选择的工作和专业无关
首页 > 专业知识

PHP网站开发常用的正则表达式

时间:2019-01-02 19:48:24 [来源]:郑州PHP培训学校

   PHP网站开发常用的正则表达式

  一、校验数字的表达式
  数字:^[0-9]*$
  n位的数字:^\d{n}$
  至少n位的数字:^\d{n,}$
  m-n位的数字:^\d{m,n}$
  零和非零开头的数字:^(0|[1-9][0-9]*)$
  非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
  带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
  正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
  有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
  有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
  非零的正整数:^[1-9]\d*$或^([1-9][0-9]*){1,3}$或^\+?[1-9][0-9]*$
  非零的负整数:^\-[1-9][]0-9″*$或^-[1-9]\d*$
  非负整数:^\d+$或^[1-9]\d*|0$
  非正整数:^-[1-9]\d*|0$或^((-\d+)|(0+))$
  非负浮点数:^\d+(\.\d+)?$或^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
  非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$或^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
  正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$或^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
  负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$或^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
  浮点数:^(-?\d+)(\.\d+)?$或^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
  二、校验字符的表达式
  汉字:^[\u4e00-\u9fa5]{0,}$
  英文和数字:^[A-Za-z0-9]+$或^[A-Za-z0-9]{4,40}$
  长度为3-20的所有字符:^.{3,20}$
  由26个英文字母组成的字符串:^[A-Za-z]+$
  由26个大写英文字母组成的字符串:^[A-Z]+$
  由26个小写英文字母组成的字符串:^[a-z]+$
  由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  由数字、26个英文字母或者下划线组成的字符串:^\w+$或^\w{3,20}$
  中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$或^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  可以输入含有^%&',;=?$\”等字符:[^%&',;=?$\x22]+
  禁止输入含有~的字符:[^~\x22]+
  三、特殊需求表达式
  Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
  域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
  InternetURL:[a-zA-z]+://[^\s]*或^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
  手机号码:^(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}$
  电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^($$\d{3,4}-)|\d{3.4}-)?\d{7,8}$
  国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
  身份证号(15位、18位数字):^\d{15}|\d{18}$
  短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$或^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
  帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
  日期格式:^\d{4}-\d{1,2}-\d{1,2}
  一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
  一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
  钱的输入格式:
  有四种钱的表示形式我们可以接受:”10000.00″和“10,000.00″,和没有“分”的“10000″和“10,000″:^[1-9][0-9]*$
  这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
  一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
  这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
  必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是“10″和“10.2″是通过的:^[0-9]+(.[0-9]{2})?$
  这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
  这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
  1到3个数字,后面跟着任意个逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
  备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
  xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
  中文字符的正则表达式:[\u4e00-\u9fa5]
  双字节字符:[^\x00-\xff](包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
  空白行的正则表达式:\n\s*\r(可以用来删除空白行)
  HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*?/>(网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
  首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$)(可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
  腾讯QQ号:[1-9][0-9]{4,}(腾讯QQ号从10000开始)
  中国邮政编码:[1-9]\d{5}(?!\d)(中国邮政编码为6位数字)
  IP地址:\d+\.\d+\.\d+\.\d+(提取IP地址时有用)
  正则表达式的五个成功习惯
  正则表达式难于书写、难于阅读、难于维护,经常错误匹配意料不到的文本或者错过了有效的文本,这些问题都是由正则表达式的表现和能力引起的。每个元字符(metacharacter)的能力和细微差别组合在一起,使得代码不借助于智力技巧就无法解释。
  许多包含一定特性的工具使阅读和编写正则表达式变得容易了,但是它们又很不符合习惯。对于很多程序员来说,书写正则表达式就是一种魔法艺术。他们坚持自己所知道的特征并持有绝对乐观的态度。如果你愿意采用本文所探讨的五个习惯,你将可以让你设计的正则表达式经受的住反复试验。
  本文将使用Perl、PHP和Python语言作为代码示例,但是本文的建议几乎适用于任何替换表达式(regex)的执行。
  一、使用空格和注释
  对于大部分程序员来说,在一个正则表达式环境里使用空格和缩进排列都不成问题,如果他们没有这么做一定会被同行甚至外行人士看笑话。几乎每个人都知道把代码挤在一行会难于阅读、书写和维护。对于正则表达式又有什么不同呢?
  大部分替换表达式工具都具有扩展的空格特性,这允许程序员把他们的正则表达式扩展为多行,并在每一行结尾加上注释。为什么只有少部分程序员利用这个特性呢?Perl 6的正则表达式默认就是扩展空格的模式。不要再让语言替你默认扩展空格了,自己主动利用吧。
  处理更加复杂的正则表达式时,空格和注释就更能体现出其重要性。假设下面的正则表达式用于匹配美国的电话号码:
  \(?\d{3}\)? ?\d{3}[-.]\d{4}
  这个正则表达式匹配电话号码如“(314)555-4000”的形式,你认为这个正则表达式是否匹配“314-555-4000”或者“555- 4000”呢?答案是两种都不匹配。写上这么一行代码隐蔽了缺点和设计结果本身,电话区号是需要的,但是正则表达式在区号和前缀之间缺少一个分隔符号的说明。
  把这一行代码分成几行并加上注释将把缺点暴露无疑,修改起来显然更容易一些。
  在Perl语言里面应该是如下形式:
  /
  \(?     # 可选圆括号
  \d{3} # 必须的电话区号
  \)?     # 可选圆括号
  [-\s.]? # 分隔符号可以是破折号、空格或者句点
  \d{3} # 三位数前缀
  [-.]    # 另一个分隔符号
  \d{4} # 四位数电话号码
  /x
  改写过的正则表达式现在在电话区号后有一个可选择的分隔符号,这样它应该是匹配“314-555-4000”的,然而电话区号还是必须的。另一个程序员如果需要把电话区号变为可选项则可以迅速看出它现在不是可选的,一个小小的改动就可以解决这个问题。
  二、书写测试
  一共有三个层次的测试,每一层为你的代码加上一层可靠性。首先,你需要认真想想你需要匹配什么代码以及你是否能够处理错误匹配。其次,你需要利用数据实例来测试正则表达式。最后,你需要正式通过一个测试小组的测试。
  决定匹配什么其实就是在匹配错误结果和错过正确结果之间寻求一个平衡点。如果你的正则表达式过于严格,它将会错过一些正确匹配;如果它过于宽松,它将会产生一个错误匹配。一旦某个正则表达式发放到实际代码当中,你可能不会两者都注意到。考虑一下上面电话号码的例子,它将会匹配“800-555-4000  = -5355”。错误的匹配其实很难发现,所以提前规划做好测试是很重要的。
  还是使用电话号码的例子,如果你在Web表单里面确认一个电话号码,你可能只要满足于任何格式的十位数字。但是,如果你想从大量文本里面分离电话号码,你可能需要很认证的排除不符合要求的错误匹配。
  在考虑你想匹配的数据的时候,写下一些案例情况。针对案例情况写下一些代码来测试你的正则表达式。任何复杂的正则表达式都最好写个小程序测试一下,可以采用下面的具体形式。
  在Perl语言里面:
  #!/usr/bin/perl
  my @tests = ( "314-555-4000",
  "800-555-4400",
  "(314)555-4000",
  "314.555.4000",
  "555-4000",
  "aasdklfjklas",
  "1234-123-12345"
  );
  foreach my $test (@tests) {
  if ( $test =~ m/
  \(?     # 可选圆括号
  \d{3} # 必须的电话区号
  \)?     # 可选圆括号
  [-\s.]? # 分隔符号可以是破折号、空格或者句点
  \d{3} # 三位数前缀
  [-\s.]  # 另一个分隔符号
  \d{4} # 四位数电话号码
  /x ) {
  print "Matched on $test\n";
  }
  else {
  print "Failed match on $test\n";
  }
  }
  在PHP语言里面:
  ;
  在Python语言里面:
  import re
  tests = ["314-555-4000",
  "800-555-4400",
  "(314)555-4000",
  "314.555.4000",
  "555-4000",
  "aasdklfjklas",
  "1234-123-12345"
  ]
  pattern = r'''
  \(?                 # 可选圆括号
  \d{3} # 必须的电话区号
  \)?     # 可选圆括号
  [-\s.]? # 分隔符号可以是破折号、空格或者句点
  \d{3} # 三位数前缀
  [-\s.]  # 另一个分隔符号
  \d{4} # 四位数电话号码
  '''
  regex = re.compile( pattern, re.VERBOSE )
  for test in tests:
  if regex.match(test):
  print "Matched on", test, "\n"
  else:
  print "Failed match on", test, "\n"
  运行测试代码将会发现另一个问题:它匹配“1234-123-12345”。
  理论上,你需要整合整个程序所有的测试到一个测试小组里面。即使你现在还没有测试小组,你的正则表达式测试也会是一个小组的良好基础,现在正是开始创建的好机会。即使现在还不是创建的合适时间,你也应该在每次修改以后运行测试一下正则表达式。这里花费一小段时间将会减少你很多麻烦事。
  三、为交替操作分组
  交替操作符号(|)的优先级很低,这意味着它经常交替超过程序员所设计的那样。比如,从文本里面抽取Email地址的正则表达式可能如下:
  ^CC:|To:(.*)
  上面的尝试是不正确的,但是这个bug往往不被注意。上面代码的意图是找到“CC:”或者“To:”开始的文本,然后在这一行的后面部分提取Email地址。
  不幸的是,如果某一行中间出现“To:”,那么这个正则表达式将捕获不到任何以“CC:”开始的一行,而是抽取几个随机的文本。坦白的说,正则表达式匹配 “CC:”开始的一行,但是什么都捕获不到;或者匹配任何包含“To:”的一行,但是把这行的剩余文本都捕获了。通常情况下,这个正则表达式会捕获大量 Email地址,所有没有人会注意这个bug。
  如果要符合实际意图,那么你应该加入括号说明清楚,正则表达式如下:
  (^CC:)|(To:(.*))
  如果真正意图是捕获以“CC:”或者“To:”开始的文本行的剩余部分,那么正确的正则表达式如下:
  ^(CC:|To:)(.*)
  这是一个普遍的不完全匹配的bug,如果你养成为交替操作分组的习惯,你就会避免这个错误。
  四、使用宽松数量词
  很多程序员避免使用宽松数量词比如“*?”、“+?”和“??”,即使它们会使这个表达式易于书写和理解。
  宽松数量词可以尽可能少的匹配文本,这样有助于完全匹配的成功。如果你写了“foo(.*?)bar”,那么数量词将在第一次遇到“bar”时就停止匹配,而不是在最后一次。如果你希望从“foo###bar+++bar”中捕获“###”,这一点就很重要。一个严格数量词将捕获“###bar++ +”。
  假设你要从HTML文件里面捕获所有电话号码,你可能会使用我们上文讨论过的电话号码正则表达式的例子。但是,如果你知道所有电话号码都在一个表格的第一列里面,你可以使用宽松数量词写出更简单的正则表达式:
  ;;(.+?);
  很多刚起步的程序员不使用宽松数量词来否定特定种类。他们能写出下面的代码:
  ;;([^>;]+);
  这种情况下它可以正常运行,但是如果你想捕获的文本包含有你分隔的公共字符(这种情况下比如;),这将会带来很大麻烦。如果你使用了宽松数量词,你只要花上很少的时间组装字符种类就能产生新的正则表达式。
  在你知道你要捕获文本的环境结构时,宽松数量词是具有很大价值的。
  五、利用可用分界符
  Perl 和PHP语言常常使用左斜线(/)来标志一个正则表达式的开头和结尾,Python语言使用一组引号来标志开头和结尾。如果在Perl和PHP中坚持使用左斜线,你将要避免表达式中的任何斜线;如果在Python中使用引号,你将要避免使用反斜线(\)。选择不同的分界符或引号可以允许你避免一半的正则表达式。这将使得表达式易于阅读,减少由于忘记避免符号而潜在的bug。
  Perl和PHP语言允许使用任何非数字和空格字符作为分界符。如果你切换到一个新的分界符,在匹配URL或HTML标志(如“http://”或“;”)时,你就可以避免漏掉左斜线了。
  例如,“/http:\/\/(\S)*/”可以写为“#http://(\S)*#”。
  通用分界符是“#”、“!”和“|”。如果你要使用方括号、尖括号或者花括号,只要保持前后配对出现就可以了。下面就是一些通用分界符的示例:
  #…# !…! {…} s|…|…| (Perl only) s[…][…] (Perl only) s;/…/ (Perl only)
  在Python中,正则表达式首先会被当作一个字符串。如果你使用引号作为分界符,你将漏掉所有反斜线。但是你可以使用“r''”字符串避免这个问题。如果针对“re.VERBOSE”选项使用三个连续单引号,它将允许你包含换行。例如 regex = "(
  [url=file://w+)(//d]\\w+)(\\d[/url]
  +)"可以写出下面的形式:
  regex = r'''
  (\w+)
  (\d+)
  '''
  小结:本文的建议主要着眼于正则表达式的可读性,在开发中养成这些习惯,你将会更加清晰的考虑设计和表达式的结构,这将有助于减少bug和代码的维护,如果你自己就是这个代码的维护者你将倍感轻松。

上一篇:PHP二维数组排序的具体方法介绍

下一篇:提升PHP速度全攻略都有哪些