MySQL 正则表达式函数大全
Posted 不剪发的Tony老师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 正则表达式函数大全相关的知识,希望对你有一定的参考价值。
大家好!我是只谈技术不剪发的 Tony 老师。
除了标准的 SQL 模式匹配(LIKE 运算符)功能之外,mysql 还提供了基于扩展正则表达式的模式匹配功能,类似于 Unix 操作系统中的 vi、grep 以及 sed 工具。本文给大家详细介绍一下 MySQL 中正则表达式函数和运算符的语法和使用。
如果你觉得文章有用,欢迎评论📝、点赞👍、推荐🎁
SQL 模式匹配使用 LIKE 和 NOT LIKE 运算符表示,使用下划线(_)匹配任意单个字符,使用百分号(%)匹配任意多个字符。MySQL 默认不区分字符的大小写。
正则表达式语法
正则表达式是实现复杂搜索的一种强大方法,一个正则表达式描述了一组字符串。最简单的正则表达式就是一个普通字符串,例如正则表达式“hello”只匹配字符串“hello”。
正则表达式通常包含一些特殊的结构,用于匹配多个不同的字符串。例如,正则表达式“hello|world”包含了替换操作符(|),可以匹配字符串“hello”或者字符串“world”。
“B[an]*s”是一个更复杂的正则表达式,它可以匹配字符串“Bananas”、“Baaaaas”、“Bs”以及任何以字母 B 开始、以字母 s 结束并且包含零个或者多个字母 a 或字母 n 的字符串。
下面我们就来介绍一些正则表达式中具有特殊意义的字符和结构,REGEXP_LIKE 是一个正则表达式函数,具体介绍参考下文。
-
字符 ^ 匹配字符串的开始,例如:
mysql> SELECT REGEXP_LIKE('fofo', '^fo'); -> 1 mysql> SELECT REGEXP_LIKE('tofo', '^fo'); -> 0
-
字符 $ 匹配字符串的结束,例如:
mysql> SELECT REGEXP_LIKE('fo\\no', '^fo\\no$'); -> 1 mysql> SELECT REGEXP_LIKE('fo\\no', '^fo$'); -> 0
-
字符 . 匹配任意字符(包括回车和换行。如果想要匹配字符串内部的回车和换行,需要使用多行匹配,可以指定匹配控制符 m 或者在模式修饰符中指定 ?m)。例如:
mysql> SELECT REGEXP_LIKE('fofo', '^f.*$'); -> 1 mysql> SELECT REGEXP_LIKE('fo\\r\\nfo', '^f.*$'); -> 0 mysql> SELECT REGEXP_LIKE('fo\\r\\nfo', '^f.*$', 'm'); -> 1 mysql> SELECT REGEXP_LIKE('fo\\r\\nfo', '(?m)^f.*$'); -> 1
-
a* 匹配零个或者多个字符串 a,例如:
mysql> SELECT REGEXP_LIKE('Ban', '^Ba*n'); -> 1 mysql> SELECT REGEXP_LIKE('Baaan', '^Ba*n'); -> 1 mysql> SELECT REGEXP_LIKE('Bn', '^Ba*n'); -> 1
-
a+ 匹配一个或者多个字符 a,例如:
mysql> SELECT REGEXP_LIKE('Ban', '^Ba+n'); -> 1 mysql> SELECT REGEXP_LIKE('Bn', '^Ba+n'); -> 0
-
a? 匹配零个或者一个字符 a,例如:
mysql> SELECT REGEXP_LIKE('Bn', '^Ba?n'); -> 1 mysql> SELECT REGEXP_LIKE('Ban', '^Ba?n'); -> 1 mysql> SELECT REGEXP_LIKE('Baan', '^Ba?n'); -> 0
-
de|abc 表示二选一,匹配字符串 de 或者 abc。例如:
mysql> SELECT REGEXP_LIKE('pi', 'pi|apa'); -> 1 mysql> SELECT REGEXP_LIKE('axe', 'pi|apa'); -> 0 mysql> SELECT REGEXP_LIKE('apa', 'pi|apa'); -> 1 mysql> SELECT REGEXP_LIKE('apa', '^(pi|apa)$'); -> 1 mysql> SELECT REGEXP_LIKE('pi', '^(pi|apa)$'); -> 1 mysql> SELECT REGEXP_LIKE('pix', '^(pi|apa)$'); -> 0
-
(abc)* 匹配零个或者多个字符串 abc,例如:
mysql> SELECT REGEXP_LIKE('pi', '^(pi)*$'); -> 1 mysql> SELECT REGEXP_LIKE('pip', '^(pi)*$'); -> 0 mysql> SELECT REGEXP_LIKE('pipi', '^(pi)*$'); -> 1
-
{1}, {2,3} 表示匹配指定次数。{n} 和 {m,n} 提供一种更通用的编写正则表达式的方法,用于多次匹配前一个元素(或者一组元素)。m 和 n 都是整数。
- a* 等价于 a{0,}。
- a+ 等价于 a{1,}。
- a? 等价于 a{0,1}。
进一步来说,a{n} 表示字符 a 出现了 n 次;a{n,} 表示字符 a 出现了 n 次以上;a{m,n} 表示字符 a 出现了 m 到 n 次,m 必须小于 n。
mysql> SELECT REGEXP_LIKE('abcde', 'a[bcd]{2}e'); -> 0 mysql> SELECT REGEXP_LIKE('abcde', 'a[bcd]{3}e'); -> 1 mysql> SELECT REGEXP_LIKE('abcde', 'a[bcd]{1,10}e'); -> 1
-
[a-dX] 匹配字符 a、b、c、d 或者 X,[^a-dX] 匹配非 a、b、c、d 或者 X 的其他字符。- 表示匹配两个字符之间的所有字符,例如 [0-9] 表示匹配任一数字。如果想要包含字符 ] 自身,它必须写在 [ 的后面;如果想要包含字符 - 自身,它必须是括号内的第一个或者最后一个字符。其他任何没有特殊意义的字符只匹配它自己。例如:
mysql> SELECT REGEXP_LIKE('aXbc', '[a-dXYZ]'); -> 1 mysql> SELECT REGEXP_LIKE('aXbc', '^[a-dXYZ]$'); -> 0 mysql> SELECT REGEXP_LIKE('aXbc', '^[a-dXYZ]+$'); -> 1 mysql> SELECT REGEXP_LIKE('aXbc', '^[^a-dXYZ]+$'); -> 0 mysql> SELECT REGEXP_LIKE('gheis', '^[^a-dXYZ]+$'); -> 1 mysql> SELECT REGEXP_LIKE('gheisa', '^[^a-dXYZ]+$'); -> 0
[=character_class=],当 [=character_class=] 出现在另一个方括号内时表示一个等价字符类。它可以匹配拥有相同排序规则值的所有字符。例如,如果 o 和 (+) 是一个等价类,[[=o=]]、[[=(+)=]] 和 [o(+)] 作用相同。等价类不能作为范围匹配的开始或者结束。
-
[:character_class:],当 [:character_class:] 出现在另一个方括号内时表示一个字符类,它可以匹配该字符类种的所有字符。下表列出了标准的字符类名称,特定的本地化设置可能还会提供其他的字符类。字符类不能作为范围匹配的开始或者结束。
字符类名称 含义 alnum 字母数字 alpha 字母 blank 空白字符 cntrl 控制字符 digit 数字 graph 图形字符 lower 小写字母 print 图形或者空白字符 punct 标点符号 space 空格、制表符、换行符以及回车符 upper 大写字母 xdigit 十六进制数字
例如:
mysql> SELECT REGEXP_LIKE('justalnums', '[[:alnum:]]+'); -> 1
mysql> SELECT REGEXP_LIKE('!!', '[[:alnum:]]+'); -> 0
如果想要在正则表达式种匹配特殊字符,可以在该字符前增加两个反斜线(\\)。MySQL 解析器会解释其中一个反斜线,正则表达式代码库会解释另一个反斜线。例如,如果想要匹配字符串 1+2 ,其中字符 + 是一个特殊字符,下面只有最后一个语句能够正确匹配:
mysql> SELECT REGEXP_LIKE('1+2', '1+2'); -> 0
mysql> SELECT REGEXP_LIKE('1+2', '1\\+2'); -> 0
mysql> SELECT REGEXP_LIKE('1+2', '1\\\\+2'); -> 1
正则表达式函数
REGEXP_LIKE
REGEXP_LIKE(expr, pat[, match_type]) 函数当字符串 expr 匹配正则表达式模式 pat 时返回 1,否则返回 0 。如果 expr 或者 pat 为 NULL,函数返回 NULL。
关于正则表达式模式的语法可以参考上一节内容,模式不一定是字符串常量。例如,模式可以是一个字符串表达式或者表中的字段。
可选的 match_type 参数指定了执行模式匹配的一些行为,可以是以下字符的组合:
- c 表示区分大小写。
- i 表示不区分大小写,默认值。
- m 表示多行模式。这种模式可以识别字符串中的行终止符。默认情况下只在字符串的开始和结尾匹配行终止符。
- n 表示字符 . 可以匹配行终止符。默认情况下,. 匹配字符时遇到一行的结尾时终止匹配。
- u 表示 Unix 行终止符。只有换行符会被 .、^ 以及 $ 匹配为一行的终止。
如果 match_type 选项中指定了互相矛盾的方式,将会使用最后指定的方式。
默认情况下,正则表达式运算使用 expr 和 pat 的字符集和排序规则决定字符的类型和比较结果。如果这两个参数的字符集和排序规则不同,将会使用 Section 10.8.4, “Collation Coercibility in Expressions” 中指定的规则进行转换。通过在参数中显式指定排序规则,可以修改默认的比较结果:
mysql> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE');
+---------------------------------------+
| REGEXP_LIKE('CamelCase', 'CAMELCASE') |
+---------------------------------------+
| 1 |
+---------------------------------------+
mysql> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs);
+------------------------------------------------------------------+
| REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs) |
+------------------------------------------------------------------+
| 0 |
+------------------------------------------------------------------+
match_type 可以通过指定 c 或者 i 决定是否区分大小写。但是有一个例外:如果任何参数是二进制字符串,使用区分大小写的方式进行匹配,即使 match_type 包含了字符 i。
注意:MySQL 使用 C 语言转义语法(例如,\\n 代表了换行符)。如果想要在 expr 或者 pat 参数中使用字面值 \\,必须写两次。除非设置了 SQL 模式 NO_BACKSLASH_ESCAPES,表示不使用转义字符。
mysql> SELECT REGEXP_LIKE('Michael!', '.*');
+-------------------------------+
| REGEXP_LIKE('Michael!', '.*') |
+-------------------------------+
| 1 |
+-------------------------------+
mysql> SELECT REGEXP_LIKE('new*\\n*line', 'new\\\\*.\\\\*line');
+----------------------------------------------+
| REGEXP_LIKE('new*\\n*line', 'new\\\\*.\\\\*line') |
+----------------------------------------------+
| 0 |
+----------------------------------------------+
mysql> SELECT REGEXP_LIKE('a', '^[a-d]');
+----------------------------+
| REGEXP_LIKE('a', '^[a-d]') |
+----------------------------+
| 1 |
+----------------------------+
mysql> SELECT REGEXP_LIKE('abc', 'ABC');
+---------------------------+
| REGEXP_LIKE('abc', 'ABC') |
+---------------------------+
| 1 |
+---------------------------+
mysql> SELECT REGEXP_LIKE('abc', 'ABC', 'c');
+--------------------------------+
| REGEXP_LIKE('abc', 'ABC', 'c') |
+--------------------------------+
| 0 |
+--------------------------------+
REGEXP
REGEXP 运算符是 REGEXP_LIKE() 函数的同义词,使用默认的 match_type 参数。例如:
mysql> SELECT 'Michael!' REGEXP '.*';
+------------------------+
| 'Michael!' REGEXP '.*' |
+------------------------+
| 1 |
+------------------------+
mysql> SELECT 'new*\\n*line' REGEXP 'new\\\\*.\\\\*line';
+---------------------------------------+
| 'new*\\n*line' REGEXP 'new\\\\*.\\\\*line' |
+---------------------------------------+
| 0 |
+---------------------------------------+
mysql> SELECT 'a' REGEXP '^[a-d]';
+---------------------+
| 'a' REGEXP '^[a-d]' |
+---------------------+
| 1 |
+---------------------+
另外,expr NOT REGEXP pat
表示NOT (expr REGEXP pat)
,也就是不匹配某个正则表达式。
RLIKE
RLIKE 运算符也是 REGEXP_LIKE() 函数的同义词,使用默认的 match_type 参数。
同样,expr NOT RLIKE
pat等价于NOT (expr REGEXP pat)
,也就是不匹配某个正则表达式。
REGEXP_INSTR
REGEXP_INSTR(expr, pat[, pos[, occurrence[, return_option[, match_type]]]]) 函数返回字符串 expr 中匹配模式 pat 的子串的位置,如果没有找到匹配的子串则返回 0。如果 expr 或者 pat 为 NULL,函数返回 NULL。字符的位置从 1 开始。
REGEXP_INSTR() 函数包含以下可选参数:
- pos 表示从字符串 expr 的指定位置开始查找。默认从第 1 个字符开始匹配。
- occurrence 表示返回第几次匹配的结果。默认返回第 1 次匹配的子串位置。
- return_option 表示返回位置的类型。如果该参数为 0(默认值),返回子串的第一个字符的位置;如果该参数为 1,返回子串之后的第一个字符的位置。
- match_type 表示匹配的方式,参数和上面的 REGEXP_LIKE() 函数一致。
例如:
mysql> SELECT REGEXP_INSTR('dog cat dog', 'dog');
+------------------------------------+
| REGEXP_INSTR('dog cat dog', 'dog') |
+------------------------------------+
| 1 |
+------------------------------------+
mysql> SELECT REGEXP_INSTR('dog cat dog', 'dog', 2);
+---------------------------------------+
| REGEXP_INSTR('dog cat dog', 'dog', 2) |
+---------------------------------------+
| 9 |
+---------------------------------------+
mysql> SELECT REGEXP_INSTR('aa aaa aaaa', 'a{2}');
+-------------------------------------+
| REGEXP_INSTR('aa aaa aaaa', 'a{2}') |
+-------------------------------------+
| 1 |
+-------------------------------------+
mysql> SELECT REGEXP_INSTR('aa aaa aaaa', 'a{4}');
+-------------------------------------+
| REGEXP_INSTR('aa aaa aaaa', 'a{4}') |
+-------------------------------------+
| 8 |
+-------------------------------------+
REGEXP_SUBSTR
REGEXP_SUBSTR(expr, pat[, pos[, occurrence[, match_type]]]) 函数返回字符串 expr 中匹配模式 pat 的子串,如果没有找到匹配的子串则返回 NULL。如果 expr 或者 pat 为 NULL,函数返回 NULL。
REGEXP_SUBSTR() 函数支持以下可选的参数:
- pos 表示从字符串 expr 的指定位置开始查找。默认从第 1 个字符开始匹配。
- occurrence 表示返回第几次匹配的子串。默认返回第 1 次匹配的子串。
- match_type 表示匹配的方式,参数和上面的 REGEXP_LIKE() 函数一致。
例如:
mysql> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+');
+----------------------------------------+
| REGEXP_SUBSTR('abc def ghi', '[a-z]+') |
+----------------------------------------+
| abc |
+----------------------------------------+
mysql> SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3);
+----------------------------------------------+
| REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3) |
+----------------------------------------------+
| ghi |
+----------------------------------------------+
MySQL 8.0.17 版本之前该函数返回的字符集为 UTF-16 ,MySQL 8.0.17 版本开始返回的字符集和排序规则与被搜索的字符串相同。
REGEXP_REPLACE
REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]]) 函数将字符串 expr 中匹配模式 pat 的子串替换为 repl 并返回替换后的结果。如果 expr、pat 或者 repl 为 NULL,函数返回 NULL。
REGEXP_REPLACE() 函数支持以下可选参数:
- pos 表示从字符串 expr 的指定位置开始查找。默认从第 1 个字符开始匹配。
- occurrence 表示替换第几次匹配的子串。默认值为 0,表示替换所有匹配的子串。
- match_type 表示匹配的方式,参数和上面的 REGEXP_LIKE() 函数一致。
例如:
mysql> SELECT REGEXP_REPLACE('a b c', 'b', 'X');
+-----------------------------------+
| REGEXP_REPLACE('a b c', 'b', 'X') |
+-----------------------------------+
| a X c |
+-----------------------------------+
mysql> SELECT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3);
+----------------------------------------------------+
| REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3) |
+----------------------------------------------------+
| abc def X |
+----------------------------------------------------+
MySQL 8.0.17 版本之前该函数返回的字符集为 UTF-16 ,MySQL 8.0.17 版本开始返回的字符集和排序规则与被搜索的字符串相同。
正则表达式资源控制
REGEXP_LIKE() 以及相关函数使用的系统资源可以通过以下变量进行控制:
- 正则表达式匹配引擎需要使用内容作为内部的堆栈。我们可以通过系统变量 regexp_stack_limit 设置该堆栈允许占用的最大内存(字节)。
- 正则表达式匹配引擎分步骤执行操作。我们可以通过系统变量 regexp_time_limit 控制引擎允许执行的最多步骤(从而间接地控制了执行时间)。由于该变量通过执行步骤进行设置,因此它只会间接地影响执行时间。通常的执行时间以毫秒为单位。
注意事项
MySQL 8.0.4 之前版本使用 Henry Spencer 正则表达式代码库实现正则表达式操作,而不是现在的 Unicode 国际组件(ICU)。这两者之间的一些差异可能会影响应用程序:
-
对于 Henry Spencer 代码库,REGEXP 和 RLIKE 操作符以字节为单位进行查找,因此它们不具有多字节安全性,可能会对多字节字符集的匹配产生错误。另外,这些操作符使用字节值进行比较,重音字符可能会被认为与相应非重音字符不相等,即使排序规则中认为它们相等。
ICU 完全支持 Unicode,并且具有多字节安全性。正则表达式函数将所有的字符串看作 UTF-16 字符串。需要注意的是,所有的下标位置都是基于 16 比特段,而不是代码点(字符编码值)。这就意味着长度超过一个 16 比特段的字符可能会返回意料之外的结果,例如:
mysql> SELECT REGEXP_INSTR('🍣🍣b', 'b'); +--------------------------+ | REGEXP_INSTR('??b', 'b') | +--------------------------+ | 5 | +--------------------------+ 1 row in set (0.00 sec) mysql> SELECT REGEXP_INSTR('🍣🍣bxxx', 'b', 4); +--------------------------------+ | REGEXP_INSTR('??bxxx', 'b', 4) | +--------------------------------+ | 5 | +--------------------------------+ 1 row in set (0.00 sec)
Unicode 基本多语言平面之内的字符(包含了大多数现代语言中的字符)在这方面是安全的:
mysql> SELECT REGEXP_INSTR('бжb', 'b'); +----------------------------+ | REGEXP_INSTR('бжb', 'b') | +----------------------------+ | 3 | +----------------------------+ 1 row in set (0.00 sec) mysql> SELECT REGEXP_INSTR('עבb', 'b'); +----------------------------+ | REGEXP_INSTR('עבb', 'b') | +----------------------------+ | 3 | +----------------------------+ 1 row in set (0.00 sec) mysql> SELECT REGEXP_INSTR('µå周çб', '周'); +------------------------------------+ | REGEXP_INSTR('µå周çб', '周') | +------------------------------------+ | 3 | +------------------------------------+ 1 row in set (0.00 sec)
表情符号,例如前面两个示例中的寿司符号 🍣(U+1F363),不属于基本多语言平面,而属于 Unicode 补充多语言平面。REGEXP_SUBSTR() 或相关函数处理表情符号或者其他 4 字节字符时,如果从某个字符中间开始查找也会产生问题。以下两个示例分别从第一个参数的第二个 2字节位置开始查找,第一个示例对于 2 字节(BMP)字符能够正常返回结果,第二个示例对于包含 4 字节字符的数据返回了错误的结果,因为第一个 2 字节被拆分了,从而导致后面的字符数据未能正确解析。
mysql> SELECT REGEXP_SUBSTR('周周周周', '.*', 2); +以上是关于MySQL 正则表达式函数大全的主要内容,如果未能解决你的问题,请参考以下文章