本文我们来详细介绍一下正则表达式,以及在Hive中通过正则匹配抽取、替换字符串的函数:
1. regexp_extract
2. regexp_replace
这里依旧借用百度百科的讲解:
正则表达式(Regular Expression,在代码中常Hive简写为regexp),又称规则表达式,是计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式由一些普通字符和一些元字符组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义,我们下面解释。在最简单的情况下,一个正则表达式看上去就是一个普通的查找串。例如,正则表达式"testing"中没有包含任何元字符,它可以匹配"testing"、"testing123"、"123testing"等任何包含"testing"的字符串,但是不能匹配"Testing"。
不过要想真正的用好正则表达式,最重要的是正确的使用各种元字符。下表列出了常用的元字符及对其简短的描述:
元字符 |
描述 |
\ |
转义字符。例如,“\n”代表换行符,如果想表示"\n"这个字符串,需要使用"\\n"来表示,也就是说"\\"代表字符"\" |
^ |
匹配输入字行首。"^a"代表以a开头的任意字符串 |
$ |
匹配输入行尾。"a$"代表以a结尾的任意字符串 |
* |
匹配前面的子表达式0次或多次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等价于{0,}。 |
+ |
匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。 |
? |
匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等价于{0,1}。 |
{n} |
n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配到“Bob”中的“o”,但是能匹配“food”中的两个o。 |
{n,} |
n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。 |
{n,m} |
m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,后三个o为一组。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。 |
? |
当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。例如,对于字符串“oooo”,“o+”将尽可能多地匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少地匹配“o”,得到结果 ['o', 'o', 'o', 'o'] |
. |
匹配除“\n”和"\r"之外的任何单个字符。要匹配包括“\n”和"\r"在内的任何字符,请使用像“[\s\S]”的模式。 |
x|y |
匹配x或y。例如,“z|food”能匹配“z”或“food”(此处请谨慎)。“[z|f]ood”则匹配“zood”或“food”。 |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。 |
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”任一字符。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。 注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身. |
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。 |
\d |
匹配一个数字字符。等价于[0-9]。 |
\D |
匹配一个非数字字符。等价于[^0-9]。 |
\n |
匹配一个换行符。 |
\r |
匹配一个回车符。 |
\s |
匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。 |
\S |
匹配任何可见字符。等价于[^ \f\n\r\t\v]。 |
\t |
匹配一个制表符。 |
\v |
匹配一个垂直制表符。 |
\w |
匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。 |
\W |
匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。 |
( ) | 将( 和 ) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。 |
. [ ] ^ $ 这四个字符是基础的正则表达式。正则难理解因为里面有一个等价的概念,这个概念大大增加了理解难度,让很多初学者看起来会懵,如果把等价都恢复成原始写法,自己书写正则就超级简单了,就像说话一样去写你的正则了:
等价:
等价是等同于的意思,表示同样的功能,用不同符号来书写。
?,*,+,\d,\w 都是等价字符
?等价于匹配长度{0,1}
*等价于匹配长度{0,}
+等价于匹配长度{1,}
\d等价于[0-9]
\D等价于[^0-9]
\w等价于[A-Za-z_0-9]
\W等价于[^A-Za-z_0-9]
常用运算符与表达式:
^ 开始
() 域段
[] 包含,默认是一个字符长度
[^] 不包含,默认是一个字符长度
{n,m} 匹配长度
. 任何单个字符(\. 字符点)
| 或
\ 转义
$ 结尾
[A-Z] 26个大写字母
[a-z] 26个小写字母
[0-9] 0至9数字
[A-Za-z0-9] 26个大写字母、26个小写字母和0至9数字
, 分割
分割语法:
[A,H,T,W] 包含A或H或T或W字母
[a,h,t,w] 包含a或h或t或w字母
[0,3,6,8] 包含0或3或6或8数字
语法与释义:
基础语法 "^([]{})([]{})([]{})$"
正则字符串 = "开始([包含内容]{长度})([包含内容]{长度})([包含内容]{长度})结束"
?,*,+,\d,\w 这些都是简写的,完全可以用[]和{}代替,初学者可以忽略?,*,+,\d,\w一些简写标示符,学会了基础使用再按表自己去等价替换。
实例:
字符串:tel:086-0666-88810009999
原始正则:"^tel:[0-9]{1,3}-[0][0-9]{2,3}-[0-9]{8,11}$"
速记理解:开始 "tel:普通文本"[0-9数字]{1至3位}"-普通文本"[0数字][0-9数字]{2至3位}"-普通文本"[0-9数字]{8至11位} 结束"
等价简写后正则写法:"^tel:\d{1,3}-[0]\d{2,3}-\d{8,11}$"
regexp_extract(string subject, string pattern, int index)
功能:
将字符串subject按照pattern正则表达式的规则拆分,返回index指定的字符。注意,在有些情况下要使用转义字符。
第一参数 subject: 要处理的字段
第二参数 pattern: 用正则表达式匹配整个字段,然后用括号括出想要抽取的部分
w第三个参数 index:
举例:
当第三个参数取0时,返回匹配到的整个字符串
hive (app)> select regexp_extract('wwwbaiducom','(www)(b.*)(com)',0);
wwwbaiducom
当第三个参数取1时,返回匹配到的字符串中第1个括号内所匹配的字符串
hive (app)> select regexp_extract('wwwbaiducom','(www)(b.*)(com)',1);
www
当第三个参数取2时,返回匹配到的字符串中第2个括号内所匹配的字符串
hive (app)> select regexp_extract('wwwbaiducom','(www)(b.*)(com)',2);
baidu
当第三个参数取3时,返回匹配到的字符串中第3个括号内所匹配的字符串
hive (app)> select regexp_extract('wwwbaiducom','(www)(b.*)(com)',3);
com
当第三个参数取4时,因为超出括号的对数3,所以报错
hive (app)> select regexp_extract('wwwbaiducom','(www)(b.*)(com)',4);
FAILED: SemanticException [Error 10014]: Line 1:7 Wrong arguments '4': org.apache.hadoop.hive.ql.metadata.HiveException: Unable to execute method public java.lang.String org.apache.hadoop.hive.ql.udf.UDFRegExpExtract.evaluate(java.lang.String,java.lang.String,java.lang.Integer) on object org.apache.hadoop.hive.ql.udf.UDFRegExpExtract@267b678f of class org.apache.hadoop.hive.ql.udf.UDFRegExpExtract with arguments {wwwbaiducom:java.lang.String, (www)(b.*)(com):java.lang.String, 4:java.lang.Integer} of size 3
regexp_replace(string initial_string, string pattern, string replacement)
功能:
将字符串initial_string中的符合正则表达式pattern的部分替换为replacement。注意,在有些情况下要使用转义字符。
第一参数 initial_string: 要处理的字段
第二参数 pattern: 正则表达式匹配字段中想要替换的部分
第三个参数 replacement:替换成的字符串
举例:
将字符串中的baidu替换为.google.
hive (app)> select regexp_replace('wwwbaiducom','baidu','.google.');
www.google.com
有时正则匹配需要对一些特殊字符进行转义处理,比如 . 在正则表达式中表示一个任意字符,如果想在正则表达式中表示.这个字符串,就需要使用\进行转义,但是!
在Hive的CLI环境下,\也需要进行转义,所以表示一个.的正确写法是 \\.
举例:
需求:把www.baidu.com中的.替换成-
如果直接使用.,会将所有字符替换成-,因为.代表任意一个字符
hive (app)> select regexp_replace('www.baidu.com','.','-');
-------------
如果转义使用\.,仍然会将所有字符替换成-,因为\也需要转义
hive (app)> select regexp_replace('www.baidu.com','\.','-');
-------------
转义使用\\.,成功替换
hive (app)> select regexp_replace('www.baidu.com','\\.','-');
OK
_c0
www-baidu-com
在hive -e和hive -f的执行环境下,转义需要四个\,即\\\\.代表字符串.
举例:
使用\\.会转义失败,仍然将所有字符替换为-
[root@hadoop ~]# hive -e "select regexp_replace('www.baidu.com','\\.','-');"
-------------
使用\\\\.转义成功,将.正常替换为-
[root@hadoop ~]# hive -e "select regexp_replace('www.baidu.com','\\\\.','-');"
www-baidu-com
hive -f同理,需要使用\\\\.才能转义成功
[root@hadoop ~]# vim regexp.hql
vim 写入select regexp_replace('www.baidu.com','\\\\.','-');
[root@hadoop ~]# hive -f regexp.hql
www.baidu.com
能看到这里的同学,就右上角点个赞吧,3Q~