提示:上文介绍通配符的相关内容,掌握通配符的知识对理解和掌握正则表达式大有裨益。
前言
上文介绍了通配符
1,本文介绍、总结和通配符有着诸多共同点的一类符号,即正则表达式(regular expression)
。只是通配符的对象是文件、或目录,而后者对象是文本内容。
在很多地方都有正则表达式
的身影,它的作用是用来匹配指定式样的内容,个人理解为,正则表达式规定了指定式样pattern
,能匹配该指定式样的字符或字符串即为内容,内容的来源可以是文件、某个标准输入等,使用正则表达式(regular expression)
的目的就是匹配到了该内容。
正则表达式(regular expression)
的使用方法在不同的操作系统上,不同的编程语言中使用方法可能存在差异。该文针对在Lunix shell(bash)环境下,Built-in命令三剑客grep
、sed
、awk
所支持的正则表达式
的使用方法和案例的总结,此外另总结了正则表达式
的种类。
提示:以下是本篇文章正文内容,下面案例可供参考
一、正则表达式
正则表达式(Regular Expression)是一种强大的文本处理工具,它能帮助用户匹配、查找、替换复杂的文本模式。这种表达式由普通字符和特殊字符(元字符)组成,用于描述一个或多个字符串的模式。正则表达式在各种编程语言和文本处理工具中广泛应用,如Python、JavaScript、Java、C#等,以及UNIX和Windows操作系统中的各种工具。2
正则表达式分类
一般情况下,可以将其分类成基础正则表达式
,即为常用的正则表达式,另一个就是有着更多扩展功能的扩展正则表达式
,在使用扩展正则表达式
时,对应的命令需要指定形式,告知命令该表达式为扩展正则表达式
。
在多数地方,介绍正则表达式
时,都会加一个内容,就是元字符
。为什么在介绍正则表达式前要了解它呢?个人理解,正则表达式
(包括一般、扩展真正表达式)都是由两个部分组成的,一部分是普通的字符或符号,即普通文本(plain text)
或字面文本(liteal text)
,如a-z0-9A-Z_
等,另一个部分是元字符
,如*
、?
、[]
、^
等。那什么是元字符
呢?
1.1、元字符
百度词条上和csdn上多数笔友都是这样定义元字符,即:
元字符(metacharacter)
是指在正则表达式
中具有特殊含义的专用字符,它们是构成正则表达式
的基本元件,用于连接字母和数字,创建高度描述性的文本模式。元字符
赋予了正则表达式
特殊的功能,使得用户可以通过输入特殊的符号来完成查找和替换操作,而不需要像往常一样输入一个确定的内容。这些特殊字符在正则表达式
中有预定义的含义,可以匹配特定类型的字符或字符串,从而实现模糊匹配和简化字符串的目的。3
但是,在学习linux shell命令时,就接触到了一些具有特殊含义的专用字符,即通配符(wildcard character)
,通配符
是由shell处理的,而正则表达式
是给Linux
工具用的。二者包括的专用字符存在重复部分。
元字符
和通配符
都是一类专用字符,通配符
是元字符
的一部分,元字符
是特殊符号中的一部分,特殊符号个人理解可以看成是键盘上那些符号,那些被用做正则表达式
中的称为元字符
。
这里将 Linux shell 元字符列出4:
字符 | 说明 |
---|---|
IFS | 由 < space > 或 < tab > 或 < enter > 三者之一组成 |
CR | 由 < enter > 产生 |
= | 设定变量 |
$ | 做变量或运算替换 |
> | 重导向标准输出 |
< | 重导向标准输入 |
| | 命令管道符 |
& | 重导向文件控制符,将命令静默执行,忽略错误 |
() | 将其内的命令置于 nested subshell 执行,或用于运算或命令替换 |
; | 在前一个命令结束时,而忽略其返回值,继续执行下一个命令 |
&& | 在前一个命令结束时,若返回值为 true,继续执行下一个命令 |
|| | 在前一个命令结束时,若返回值为 false,继续执行下一个命令 |
! | 执行 history 中的命令 |
使用
正则表达式
最大的问题在于不止一种类型的正则表达式。在Linux中,不同的应用程序可能使用不同类型的正则表达式
。
正则表达式是由正则表达式引擎
实现的。这是一种底层软件,负责解释正则表达式并用这些模式进行文本匹配 5。
流行的Linux正则表达式引擎有:
POSIX基础正则表达式(basic regular expression,BRE)
引擎POSIX扩展正则表达式(extended regular expression,ERE)
引擎
也正是有上述不同的引擎,才有基础和扩展正则表达式
之分。
正则表达式可以分为两类,一类是基础正则表达式,另一类是扩展正则表达式。
1.2、基础正则表达式
即使用POSIX基础正则表达式
引擎来处理文本数据流,一般可以包括下几中类型:
定义BRE模式 | 所包括的字符 | 注释 |
---|---|---|
普通文本 | a-z0-9A-Z_ | 字面形式 |
锚点字符 | 脱字符 ^ 和美元符 $ | 二者可以同时使用 |
点位字符 | . | 匹配除换行符 之外的任意单个字符,多数情况下换行符 为\n ,也可以匹配空格 |
字符组 | [ ] | 匹配中括号中字符组中的任一个字符 |
排除型字符组 | [^] | 匹配中括号之外的其他任一字符,包括可以匹配空格 |
区间 | [-] | 匹配中括号内的任一字符,区间可以不连接如,[a-cx-z] 表示a-c和x-z之间的任一个字符 |
特殊的字符组 | [[:alpha:]] 、[[:alnum:]] 等 | 匹配双中括号中的任一字符,见前文,和通配符 6 一致 |
星号 | * | 匹配前一字符出现0次或者多次 |
反斜线 | \ | 将特殊符号当作普通文本使用需要在其前面加上\ |
注意1:这里存在一个很相似的概念,就是换行符和回车符,日后会给大家澄清二者的区别。
注意2:反斜线 \ 加上特殊符号用作普通字符,反斜线 \ 加上某一些普通字符会成为有着特殊作用的正则表达式。
另作介绍
1.3、扩展正则表达式
使用POSIX扩展正则表达式引擎
来处理文本数据流,不仅可以兼容基础正则表达式
,还可以支持扩展正则表达式
,扩展正则表达式
有以下几种:
定义ERE模式 | 所包括的字符 | 注释 |
---|---|---|
问号 | ? | 匹配前面字符出现0次或者1次 |
加号 | + | 匹配前面字符出现1次或者多次 |
花括号 | { } | 允许的形式包括有:{m} 表示前面字符出现m次、{m,} 表示前面字符最少出现m次、{,m} 表示前面字符最多出现m次、{m,n} 表示前面字符出现m到n次 |
竖线符号 | | | 语法形式为: expr1|expr2|... ,竖线符号允许在检查数据流时,以逻辑OR方式指定正则表达式引擎要使用多个模式。竖线左右两边的表达式可以是任意的正则表达式可用的模式符号,如[ab]|[ef]g等。注意:该符号在使用时,expr和竖线符号之间不能有空格,否则竖线符号会被认作是模式的一部分。 |
表达式分组 | ( ) | 圆括号或小括号,表示对正则表达式进行分组,分组之后每组会被视为一个整体,可以对每个分组应用特殊字符,如(a|b)?c(e|f)?等 |
二、正则表达式案例
在不同的环境下,正则表达式
的使用方法略有不同,在实际工作中,存在三种使用正则表达式的场景:
- 在linux的命令行中结合三剑客使用正则表达式(不同的
shell
可能还会不同); - 在
linux
脚本中使用脚本命令应用正则表达式
处理数据流(或许可以和第一个认为是同一类,因为用法相同,是不是绝对相同,不敢说); - 使用
gvim
(vim
)文本编辑器打开文本后,使用正则表达式
处理文本
下文使用两个实战案例:验证电话号码,解析email地址,使用笔者的linux环境来说明正则表达式
的使用方法。案例包含了上述的第一、二种场景,第三种类场景下的正则表达式的使用会另安排一个章节进行说明。
验证电话号码
案例:验证电话号码
验证中国座机号码,国内座机号码类似于下形式(大家不要纠结这个号码是不是存在,只是用这个来练习正则表达式
):
(010)xxxx-xxx
(010) xxxx-xxx
010-xxxx-xxx
010.xxxx.xxx
(02x)xxxx-xxx
(02x) xxxx-xxx
02x-xxxx-xxx
02x.xxxx.xxx
(xxxx)xxxx-xxx
(xxxx) xxxx-xxx
xxxx-xxxx-xxx
xxxx.xxxx.xxx
上号码组成是区号有三位、或四位,区号可能会使用小括号,区号后和主号之间的分隔符可能是没有、空格、短线-、或者点。主号前四位后分隔符可以是短线-、或者点。
编写脚本:可以过滤、打印符合座机号码规则的号码
- 所需文本
/home/weifexie/shell_tra [336]: cat phonelist
# reasonable phone numbers
(010)0751-075
(010) 0751-075
010-0751-075
010.0751.075
(021)0751-075
(021) 0751-075
021-0751-075
021.0751.075
(0751)0751-075
(0751) 0751-075
0751-0751-075
0751.0751.075
# un-reasonable numbers
[751.0751.075
0751.751.075
0751.0751.-75
- 脚本内容:
/home/weifexie/shell_tra [337]: cat isphone.sh
#!/usr/bin/bash
#
# usage: filter out bad phone numbers
#
# reasonable phone number as below
# (010)xxxx-xxx
# (010) xxxx-xxx
# 010-xxxx-xxx
# 010.xxxx.xxx
# (02x)xxxx-xxx
# (02x) xxxx-xxx
# 02x-xxxx-xxx
# 02x.xxxx.xxx
# (xxxx)xxxx-xxx
# (xxxx) xxxx-xxx
# xxxx-xxxx-xxx
# xxxx.xxxx.xxx
gawk --re-interval '/^\(?((010)|(02[0-9])|([0-9]{4}))\)?(| |-|\.)[0-9]{4}(-|\.)[0-9]{3}$/ {print $0}'
exit 0
- 脚本执行结果:
/home/weifexie/shell_tra [339]: cat ~/shell_tra/phonelist | ~/shell_tra/isphone.sh
(010)0751-075
(010) 0751-075
010-0751-075
010.0751.075
(021)0751-075
(021) 0751-075
021-0751-075
021.0751.075
(0751)0751-075
(0751) 0751-075
0751-0751-075
0751.0751.075
- 解析思路
^\(?((010)|(02[0-9])|([0-9]{4}))\)?(| |-|.)[0-9]{4}(-|\.)[0-9]{3}$
注意:gawk中使用花括号{}需要有‘--re-interval’
分组中还可以对其中的内容使用分组
解析email地址
案例:解析email地址
email地址可以简写成username@hostname
username 是由字母、数字、点、-、+、_符号构成的。
hostname 是由两部分组成。第一部分是 服务器名和一个或多个域名构成,服务器名和域名之间要有点符号,服务器名和域名是由字母、数字、点、-构成的。第二部分是 顶级域名,位数不少于2、不超多5,顶级域名是由字母构成的。
类似合理的email形式如:
weifexie@amd.com
weifeng_xie@amd.com
2521417406@qq.com
编写脚本:可以过滤、打印符合email地址规则的email
- 所需文本
/home/weifexie/shell_tra [343]: cat emaillist
weifexie@amd.com
weifeng_xie@amd.com
2521417406@qq.com
weife.xie@amd.com
weifexie@amd.server.com
weifexie@amd_.com
weifexie$amd.com
weifexie@amd.com.
- 脚本内容:
/home/weifexie/shell_tra [345]: cat isemail.sh
#!/usr/bin/bash
#
# usage: filter out bad phone numbers
#
# reasonable phone number as below
# weifexie@amd.com
# weifeng_xie@amd.com
# 2521417406@qq.com
# weife.xie@amd.com
# weifexie@amd.server.com
# weifexie@amd_.com
# un-reasonable
# weifexie$amd.com
# weifexie@amd.com.
gawk --re-interval '/^[0-9a-zA-Z_\.\-\+]+@[0-9a-zA-Z_\.]+\.[a-zA-Z]{2,5}$/ {print $0}'
exit 0
- 脚本运行结果
/home/weifexie/shell_tra [346]: cat emaillist | isemail.sh
weifexie@amd.com
weifeng_xie@amd.com
2521417406@qq.com
weife.xie@amd.com
weifexie@amd.server.com
weifexie@amd_.com
- 解析思路
^[0-9a-zA-Z_\.\-\+]+@[0-9a-zA-Z_\.]+\.[a-zA-Z]{2,5}$
^[0-9a-zA-Z_\.\-\+]+ :多个字母、数字、点、-、+、_ 符号
[0-9a-zA-Z_\.]+ :多个字母、数字、点、_符号
\. :一个点
[a-zA-Z]{2,5}$ :2-5个字母结尾
总结
正则表达式是shell中处理数据必须要掌握的知识。其包括普通正则表达式和扩展正则表达式,二者是通过正则表达式引擎实现的。本文总结了正则表达式的分类,同时给出两个实际案例,将理论和实际结合,旨在掌握该知识。
念念不忘,必有回响
END
通配符(https://blog.csdn.net/qq_35628393/article/details/140042577?spm=1001.2014.3001.5501) ↩︎
百度词条正则表达式(https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215?fr=ge_ala#1) ↩︎
元字符百度词条(https://baike.baidu.com/item/%E5%85%83%E5%AD%97%E7%AC%A6/6062776?fr=ge_ala) ↩︎
Linux shell 元字符(https://www.cnblogs.com/divent/p/5762154.html) ↩︎
《Linux命令行与shell脚本编程大全(第四版)》 ↩︎
通配符(https://blog.csdn.net/qq_35628393/article/details/140042577?spm=1001.2014.3001.5501) ↩︎