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 RLIKEpat等价于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 正则表达式函数大全的主要内容,如果未能解决你的问题,请参考以下文章

    MySQL中REGEXP正则表达式使用大全

    MySQL中REGEXP正则表达式使用大全

    正则表达式-语法大全

    正则表达式大全

    编程中常用的正则表达式大全(上)

    数据清洗 常用正则表达式大全