无论是编程语言,比如Python,还是SQL,比如Hive和MySQL都提供了正则表达式用于数据及文本字符串的过滤和匹配。正则表达式不是一种完备的程序设计语言。但在绝大多数的软件产品、编程语言、实用工具和开发环境中,正则表达式都已经被实现。正则表达式的使用方法和具体功能在不同的应用程序和语言中各不相同。具体在使用时,还需要具体去查手册。
1.原理
正则表达式的底层原理是两类自动机:确定型有穷自动机和的非确定型有穷自动机。(这两个我是在编译原理这门计算机专业课程汇总学到过,这里不展开说,有兴趣的话可以自己去查阅资料)。
2.语法
2.1 匹配字符
匹配字符主要是利用各种元字符和特殊的字符集合去匹配单个字符。
模式 | 含义 |
. | 匹配任意字符。(但是Python和Hive中.无法匹配换行符。MySQL8.0中使用regexp_like()函数时可以在match_type中设定是否要匹配换行符。) |
a | 只能匹配特定字符a。(如果想要匹配b则就在正则表达式中写上b) |
[...] | 使用[和]定义一个字符集合。在进行匹配时,每次可以和这个字符集合中的任意一个匹配。比如[amk]可以匹配a,可以匹配m,也可以匹配k。 |
[^...] | ^用在字符区间里表示排除,即不能和[]中的任意一个字符进行匹配。 |
a|b | 匹配a或b |
下面是在MySQL8.0中使用regexp_like将\n与.匹配的代码
下面列出了以下可以放在[和]中的一些常见的字符区间。
模式 | 含义 |
[a-z] | 匹配从a到z中的任意一个小写字符 |
[A-Z] | 匹配从A到Z中的任意一个大写字符 |
[0-9] | 匹配从0到9中的任意一个数字 |
[\u4e00-\u9fa5] | 匹配任意一个中文汉字 |
特殊字符(以元字符\开头表示)。(MySQL中似乎不完全支持以下字符)
模式 | 含义 |
\ | 如果想要使用正则表达式匹配.,则可以在正则表达式中使用\.来表示。\叫元字符,通常作为具有特殊含义字符的开头。 |
\d | 等价于[0-9] |
\D | 等价于[^0-9] |
\s | 等价于 [ \f\n\r\t\v]。 |
\S | 等价于 [^ \f\n\r\t\v]。 |
\w | 等价于'[A-Za-z0-9_]'。 |
\W | 等价于'[^A-Za-z0-9_]'。 |
2.2 重复匹配
前一部分介绍的模式只能匹配单个字符,在这些模式后面加上一些表示匹配次数的模式,就可以匹配多个连续出现的字符和字符串。具体的模式有如下几个:
模式 | 含义 |
+ | 至少重复一次 |
* | 重复0次或任意次数 |
? | 重复0次或1次 |
{m,n} | 至少匹配m次,至多匹配n次。其中{m}就表示只匹配m次,{m,}表示重复m次或更多,{,n}表示最多重复n次或更少 |
需要特别说明的是,正则表达式有两种重复匹配模式,一种是贪婪匹配,一种是非贪婪匹配。贪婪匹配是指最大长度匹配。非贪婪匹配也叫惰性匹配,指匹配到结果就行,取最小长度匹配。在+,*,{m,n},?后面加一个?就可以将其从贪婪匹配模式转化为非贪婪匹配模式。具体代码示例如下:
import re
str_1='abbbcaac'
par_1=r'a.*c'
par_2=r'a.*?c'
result_1=re.search(par_1,str_1)[0]
result_2=re.search(par_2,str_1)[0]
print(result_1)
print(result_2)
其结果如下:
result_1 | abbbcaac |
result_2 | abbbc |
2.3 位置匹配
位置匹配用于指定应该在文本中什么地方进行匹配操作。主要有以下几种定位符:
模式 | 含义 |
^ | 匹配字符串的开始。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。 |
$ | 匹配字符串的结尾。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
\b | 匹配一个单词的边界 |
\B | 非单词边界匹配 |
这些定位符匹配的是一个位置,而不是任何实际的字符,所以这4个字符通常也被称为“锚点”。比如\b,它匹配的字符位置是:一边能够被\w匹配的字母数字下划线(应该也包括中文字符),另一边是其他内容(即被\W匹配的内容)。(貌似不同的系统中\b匹配的位置不一样,Python、MySQL、Hive都不一样)。另外,不同的系统,字符串的结束标志也不一样。
另外正则表达式有一种匹配模式叫多行匹配。在Python中通过使用re.M来启用,而在MySQL中需要在正则表达式的模式前添加(?m)是实现(比如,'^.*$'转变为多行匹配模式的写法为(?m)'^.*$')。使用多行模式匹配的时候会影响^和$的使用。
在Python中,多行模式的标志为re.M,在Hive中,在正则表达式前添加(?m)就可启动多行模式。
import re
#待匹配的字符串中有换行符
result=re.search('^\\w+$','aaaa\nedafndade')
print("result:{}".format(result[0] if result else '空'))
#待匹配的字符串中没有换行符
result_1=re.search('^\\w+$','aaaaedafndade')
print("result_1:{}".format(result_1[0] if result_1 else '空'))
#使用多行模式
result_2=re.findall('^\\w+$','aaaa\nedafndade',re.M)
print("result_2:{}".format(result_2))
其结果如下:
|
从代码实验结果可以看出,在单行模式下,如果使用了^和$,如果字符串中出现了换行符,则正则表达式找不到任何匹配。
补充:
1.Python中转义字符书写方式
python中有一些独特的语法可以用于处理包含换行符或反斜杠的字符串,比如原始字符串(用前缀r表示)。原始字符串表示不以特殊方式处理反斜杠。比如
str_1='abbbdce1111\n32ddffdafdsfdfdffa'
str_2=r'abbbdce1111\n32ddffdafdsfdfdffa'
print(str_1)
print('===========')
print(str_2)
其实验结果如下,从实验结果可以看出str_2中的‘\n’并没有被转义成换行符。需要说明的是不会'\'和任意一个字符组合都能组成一个转义字符,转义字符的类别是固定的。
abbbdce1111
32ddffdafdsfdfdffa
===========
abbbdce1111\n32ddffdafdsfdfdffa
下面在看一下正则表达式中的re.compilie()d函数是如何处理输入的字符串的。
import re
str_1=re.compile(r'\d')
print(str_1)
str_2=re.compile('\\d')
print(str_2)
str_3=re.compile('\d')
print(str_3)
print(str_1==str_2)
print(str_2==str_3)
实验结果如下。从实验结果可以看到,这三种模式书写方式最后得到的模式串是相同的。似乎他们都转化成了C语言中的书写方式。在str_2的写法中,‘\\’被转义成了‘\’。在str_3的写法中,‘\’和‘\d’本身并不能组成转义字符,所以被当做两个不同的字符。
re.compile('\\d')
re.compile('\\d')
re.compile('\\d')
True
True
从上述实验结果中可以看到,在Python中,‘\d’被当成了两个字符,\即没有进行转义,也没有被忽略。
2.Hive中转义字符书写方式
Hive中并不支持类似Python中的原始字符串,所以Python中用的正则表达式写法并不能照搬运用到Hive中。
select '1' as num, 'ww' regexp '^\w+$' as match_label
union all
select '2' as num,'abbc' regexp '^\w+$' as match_label
union all
select '3' as num, 'abbc' regexp '^\\w+$' as match_label
其结果如下:
num | match_label |
1 | 1 |
2 | 0 |
3 | 1 |
在Hive中写正则表达式时要特别注意‘\’的用法。在其它转义序列中,Hive会将反斜线忽略,仿佛没有这个反斜线,所以在第1个SQL语句中,实际的字符串为‘ww’,实际的正则表达模式为‘^w+$’。
从上图也可以看出,在Hive中,‘\’和d不能构成转义字符时,\被忽略。
另外,还需要注意,在数据库中使用regexp函数时,其结果类似于python中的re.search()函数。也就是说,在数据库中,只要带匹配的字符串中存在子串能够与正则表达式所描述的模式匹配,其返回结果就是true. 如果要想实现re.match()的作用,则需要加上匹配开始和结尾的定位符。