Mysql必知必会(4):使用正则表达式搜索(REGEXP)

本文主要介绍如何在Mysql中使用正则表达式进行搜索。html

正则表达式是一个很是大的内容,我会在以后专门写博客介绍,这里只是简介一些经常使用匹配模式git

博客文章地址:http://weiya.me/item/59.html正则表达式

简介

以前几篇文章讲解了各类各样的过滤数据条件,经过这些条件,咱们已经可以知足平常开发中大部分的工做。但假设筛选条件更加复杂一点,好比你的老板叫你从邮箱+手机号码混合注册的用户中找出手机号码注册用户,要给他们发送营销短信。这时,以前的过滤方法就不太奏效。正则表达式搜索就派上大用场。sql

简单来讲,正则表达式就是用来匹配文本的特殊字符串。好比,从文本中提取电话号码,带数字的用户名,或者提取某个特定格式的文本。数据库

并且全部语言编辑器基本上都支持正则表达式,不得不说,正则表达式已经成为开发过程当中强大而有力的工具。Mysql也不例外,那么就开始正式学习这种特殊匹配方式。编程

本文所用到的Mysql表在文章最后的附录。segmentfault

匹配字符串

匹配字符串是正则表达式最基础的应用。咱们先给出一个例子:咱们从一个用户表中查询出名字中包含有100数字的用户编程语言

图片描述

SELECT * FROM my_user WHERE `name` REGEXP '100';

图片描述

咱们获得了用户ID为1的用户:小红100编辑器

该语句中不一样于以前的语句,咱们使用REGEXP关键字表明后面为正则表达式工具

这条语句看起来和LIKE语句特别类似,并且也是可使用LIKE语句来实现。那使用正则表达式的意义何在?

缘由很简单。假设,我如今须要匹配不只仅是包含100数字的用户,而是100,200,或者300,只要是整百的都须要匹配。或者说,我须要全部名字里面包含数字的,不管什么数字。那么使用LIKE来实现就会显得十分的困难。而正则表达式就会显得十分简单。

SELECT * FROM my_user WHERE `name` REGEXP '.00'; // 匹配包含整百的名字,如100,200,300等等

表达式.00里面的点,表明的任意字符。也就是不管是1仍是2仍是9,或者是字母什么的均可以匹配,匹配任意。

图片描述

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]'; // 匹配全部名字里面包含数字的用户

图片描述

是否是来的比LIKE简单得多?上面的表达式,咱们在接下来就会详细阐述。

正则和模糊查询的区别

那么咱们什么状况下应该使用LIKE?什么状况下又适合使用正则表达式查询?

这里咱们只须要记住LIKE查询和正则查询很是重要的差异便可。

先看两个例子:

一、以前的一条语句

SELECT * FROM my_user WHERE `name` REGEXP '100';

图片描述

二、LIKE查询的实现

SELECT * FROM my_user WHERE `name` LIKE '100';

图片描述

这里咱们能够清楚的看到二者的区别:正则表达式返回了一条记录,而LIKE查询没有匹配到任何记录

结论LIKE查询匹配整个列,若是须要匹配的字符串(好比上面的100)包含在列中,那么则没法匹配成功。而正则匹配则能够匹配列值内部的值,简单来讲就是它会从第一个字符开始日后匹配,只要匹配有一个成功那么就会返回记录。这是二者重要的区别。

那么正则匹配是否也能够匹配整个字符,固然能够。不过须要涉及到另外的知识:定位符^$,下面将会做详细解释。

使用或查询

若是正则表达式仅仅就是和LIKE有那么一点儿的差异,也就不会有这么高的地位了。下面才是显示身手的时候。

或查询也叫OR查询,是条件并列查询的一种状况。相似于编程语言里面的if else只要有一个条件符合就会被匹配。

SELECT * FROM my_user WHERE `name` REGEXP '100|200';

图片描述

上面的语句查询了名字中包含了100或者200数字的用户,就是说两个数值只要匹配一个就能够返回数据。

固然你也能够给出多个或状况,他们之间使用竖线分割便可。好比:100|200|300|400

使用或查询的状况,有点儿相似于SELECT中使用OR条件链接的状况,你能够把它们想象成并入了一个正则表达式。

匹配多个字符之一

正则匹配中有一种特殊的OR匹配。

SELECT * FROM my_user WHERE `name` REGEXP '[12]';

图片描述

上面表达式中咱们使用了一个特殊的字符串[12],这个字符串的含义是:查询名字中包含有数字1或者数字2的记录,它是[1|2]的缩写。

这种,使用方括号将字符串括起来的写法,不管方括号内有多少字符串,其表达的含义都是匹配其中任意一个。

若是是[123456789]那么就表明,匹配名字中包含1或2或3或4或5或6或7或8或9的任何一个记录。

固然,字符串还能够查询被否认的状况。[^12]若是在12以前加上一个^符号,那么就表明除了1或2外的字符串。

SELECT * FROM my_user WHERE `name` REGEXP '[^12]';

图片描述

说明:表中小红100,虽然包含1,可是他包含了0。0不属于1或者2,因此被匹配。

匹配一个范围

看下咱们上面有个集合[123456789],若是每次咱们写正则时候都这么写,那么岂不是很麻烦。因此,咱们能够简化这种状况,使用一个范围[1-9]来代替这串字符串。若是是匹配全部数字,那么就会包含0,咱们可使用[0-9]来表示。

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]';

图片描述

这个表达式将会匹配出全部名字中包含数字的记录。拆开理解就是,包含0或者1或者2...或者8或者9的记录。

并且,这里的范围不只仅只能是数字,还能够是字母。好比[a-z]就是表示从字母a到字母z的全部数字,26个字母。小写完了,还有大写[A-Z]。那么咱们将其组合起来[0-9a-zA-Z]这个表达式就十分强大了,能够表示包含数字,小写字母,大写字母的全部记录。

SELECT * FROM my_user WHERE `name` REGEXP '[0-9a-zA-Z]';

图片描述

因为我名字里面没有包含字母的,因此结果和上面[0-9]相同。

匹配特殊字符串

咱们来看下下面的一条语句:

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]';

这个语句的意思是匹配名称包含全部数字的记录。0-9被方括号扩了起来,那么假设我如今就须要匹配方阔号该如何处理?

这个时候就须要用到匹配特殊字符的知识。为了匹配这些特殊的字符,咱们须要使用转义功能,就是使用(双反斜杠)做为前导。假设咱们须要匹配经常使用特殊字符便可这么写:

\\[ 匹配左方括号
\\. 匹配点号
\\] 匹配右方括号
\\| 匹配竖线
\\\ 匹配反斜杠本身自己

依次类推,其余特殊的字符串也可使用这么方式处理。

双反斜杠加上一些字母还能够表示特殊的含义。

好比:

\\f 换页
\\n 换行
\\r 回车
\\t 制表符
\\v 纵向制表符

在通常的编程语言中,转义通常使用一个反斜线,在Mysql中为何是两个才行?缘由是:Mysql本身须要一个来识别,而后Mysql会将扣除了一个反斜杠的剩余的部分彻底的交给正则表达式库解释,因此加起来就是两个了。

使用预约义字符集

虽然正则表达式提供了一些很长表示方式的缩写,好比[0-9]表示数字。[a-z]表示小写字母。可是,有些时候仍是以为复杂。因此,正则表达式还提供了一些预约义的字符类来方便咱们开发。

简单来讲,就像车牌使用苏表明江苏,而沪表明上海同样。

咱们直接给出表直接参阅。

说明
[:alnum:] 任意数字和字母。至关于[a-zA-Z0-9]
[:alpha:] 任意字符。至关于[a-zA-z]
[:blank:] 空格和制表。至关于[(双斜杠,segmentfault这里双斜杠打不出来)t]
[:cntrl:] ASCII控制字符(ASCII 0 到31和127)
[:digit:] 任意数字。至关于[0-9]
[:graph:] 与[:print:]相同,可是不包含空格
[:lower:] 任意的小写字母。至关于[a-z]
[:print:] 任意可打印字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在内的任意空白字符。
[:upper:] 任意大写字母。至关于[A-Z]
[:xdigit:] 任意十六进制的数字。至关于[a-fA-F0-9]

元字符

以前匹配的内容都是单词匹配。就是若是匹配到一次就显示,匹配不到就不显示。可是,复杂的状况有时候要求匹配不止一次。假设我须要匹配名字中包含2-3位数字的记录。这个时候就须要使用一种特殊的元字符来修饰。

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]{2,3}';

图片描述

是否是很是简单?下面具体解释它的用法。

拿出这个特殊字符串[0-9]{2,3},除去前面的[0-9]后面的{2,3}就被成为重复元字符,它的做用就是使得前面的数字重复必定的次数。

元字符 做用
* 重复0次或者屡次
+ 重复一次或者屡次。至关于{1,}
? 重复0次或者1次
{n} 重复n次
{n,} 重复至少n次
{n,m} 重复n-m次
SELECT * FROM my_user WHERE `name` REGEXP '[0-9]*'; // 匹配名字包含或者不包含数字的记录

图片描述

SELECT * FROM my_user WHERE `name` REGEXP '[0-9]{2,3}'; // 匹配名字内包含2位数或者3位数的记录

图片描述

定位元字符

除了以前的重复元字符,正则还有一种特殊的定位元字符

元字符 做用
^ 文本开始
$ 文本结尾
[[:<:]] 词的开始
[[:>:]] 词的结尾

还记得以前区别LIKE和正则表达式的例子么?LIKE是对整个字符串进行匹配,而正则是匹配到就能够。

若是如今咱们须要在邮箱+手机号码混合注册的帐号中,挑选出手机号码,那么咱们就要对帐号进行从头至尾的匹配。

好比手机号码是11位数字,也就是说a11111111111不行,可是他又具有11个数字条件。

因此咱们要求从头开始匹配到结尾,是11位数字。

SELECT * FROM my_user WHERE `name` REGEXP '^[0-9]{11}$';

为了匹配到内容,我在数据库内又加了一条记录。

图片描述

匹配结果

图片描述

附录:用户表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for my_user
-- ----------------------------
DROP TABLE IF EXISTS `my_user`;
CREATE TABLE `my_user` (
  `user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  `age` tinyint(2) NOT NULL DEFAULT '0',
  `password` varchar(40) NOT NULL,
  `code` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of my_user
-- ----------------------------
INSERT INTO `my_user` VALUES ('1', '小红100', '20', '7c4a8d09ca3762af61e59520943dc26494f8941b', '2arfs5dr6m');
INSERT INTO `my_user` VALUES ('2', '小明200', '19', '7c4a8d09ca3762af61e59520943dc26494f8941b', 'd59tg6dr5h');
INSERT INTO `my_user` VALUES ('3', '小黄350', '25', '7c4a8d09ca3762af61e59520943dc26494f8941b', 'w56tg9hjn3');
INSERT INTO `my_user` VALUES ('4', '小颖410', '25', '7c4a8d09ca3762af61e59520943dc26494f8941b', 'a5d23e9yh5');
INSERT INTO `my_user` VALUES ('5', '星空幻颖', '22', '7c4a8d09ca3762af61e59520943dc26494f8941b', '86d2sadft9');

星空幻颖,严颖

我的主页:segmentfault

相关文章
相关标签/搜索