你有你的规则,我有我的正则
开发中经常用到正则表达式,但总是靠搜索,有的结果过时或者不正确,导致浪费很多时间。与其将时间浪费在搜索上倒不如自己好好地掌握它。
正则规则
分四大类来说明: 常用符号说明、符号数目匹配、逻辑语句符号匹配、目标匹配符号。
一、常用符号说明
^
: 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\n”或”\r”之后的位置匹配。$
: 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\n”或”\r”之前的位置匹配。\
: 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,”n”匹配字符”n”。”\n”匹配换行符
二、符号数目匹配
*
: 零次或多次 匹配前面的字符或子表达式。例如,”zo*“ 匹配”z”和”zoo”。* 等效于{0,}
。+
: 一次或多次 匹配前面的字符或子表达式。例如,”zo+”与”zo”和”zoo”匹配,但与”z”不匹配。+ 等效于{1,}
。?
: 零次或一次 匹配前面的字符或子表达式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效于{0,1}
。{n}
: n 是非负整数。正好匹配 n 次。例如,”o{2}”表示此匹配两个o{n,}
: n 是非负整数。至少匹配 n 次。{n,m}
: n 和 m 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。
三、逻辑语句符号匹配
x|y
: 匹配 x 或 y。例如,’z|food’ 匹配”z”或”food”。’(z|f)ood’ 匹配”zood”或”food”。()
: 括号
四、目标匹配符号
[xyz]
: 字符集。匹配包含的任一字符。例如,”[abc]”代表当前位只能是abc三个字符中的一个[^xyz]
: 反向字符集。匹配未包含的任何字符。例如,”[^abc]
“ 则当前位不能是abc中的任意一个。[a-z]
: 字符范围。匹配指定范围内的任何字符。如:[a-z]
: 当前位匹配从a到z字符[A-Z]
: 当前位匹配从A到Z字符[0-9]
: 当前位匹配从0到9字符[a-zA-Z0-9]
: 当前位匹配从a到z,从A到Z以及从0-9的字符[a-zA-Z0-9_]
: 当前位匹配从a到z,从A到Z以及从0-9的字符和_字符[a-zA-Z0-9_-]
: 当前位匹配从a到z,从A到Z以及从0-9的字符和_与–字符
[^a-z]
: 反向范围字符。匹配不在指定的范围内的任何字符.\d
: 匹配数字,与[0-9]
等效.\D
: 匹配非数字字符,与[^0-9]
等效.\w
: 匹配任何字类字符,包括下划线。与”[A-Za-z0-9_]
“等效.\W
: 与任何非单词字符匹配。与”[^A-Za-z0-9_]
“等效。.
: 匹配除”\r\n”之外的任何单个字符。若要匹配包括”\r\n”在内的任意字符,请使用诸如”[\s\S]”之类的模式。\b
: 匹配一个字边界,即字与空格间的位置。例如,”er\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。多用于java中的正则查找与替换。\B
: 非字边界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。\s
: 匹配任何空白字符,包括空格、制表符、换页符等。与[\f\n\r\t\v]
等效。\S
: 匹配任何非空白字符。与[^\f\n\r\t\v]
等效。- 各种空白符:
\f
: 换页符匹配。等效于 \x0c 和 \cL。\n
: 换行符匹配。等效于 \x0a 和 \cJ。\r
: 匹配一个回车符。等效于 \x0d 和 \cM。\t
: 制表符匹配。与 \x09 和 \cI 等效。\v
: 垂直制表符匹配。与 \x0b 和 \cK 等效。
\xn
: 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,”\x41”匹配”A”。允许在正则表达式中使用 ASCII 代码。\un
: 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。附:Unicode编码说明,汉字Unicode编码表
常见正则
下面分别对常见的邮箱和手机号举例。
邮箱:
常见邮箱形式:
网络上正则,仅仅能匹配 1,2 两种格式:
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
满足需求正则:
- 匹配全部:
^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$
- 等价匹配:
^[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
- 或者:
^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$
- 注意java代码里需要将所有 \ 转义,要在所有 \ 前多加一个 \
java 代码:
1 2 3 4 |
public static boolean isEmail(String email) { String regex = "^(\\w)+(\\.\\w+)*@(\\w)+((\\.\\w{2,3}){1,3})$"; return email.matches(regex); } |
手机号码:
手机基本格式如下:
- 共11位:
- 13(0-9):13开头手机号第三位0-9全可以
- 14(5,7):14开头的第三位只有5(联通),7(移动)
- 15(-4):15开头的第三位除了4,其他都有,因为(154有谐音“要我死”)
- 17(3,5,6,7,8):17开头的三位有3,5,6,7,8;其中3,7为电信,5,6为联通,8为移动。
- 18(0-9):18开头的第三位0-9均可以
- 而170和171的为虚拟运营商:
1 2 3 4
1700/1701/1702(电信) 1703/1705/1706(移动) 1704/1707/1708/1709(联通) 171(联通)
虚拟商除外,匹配前三个位置数字正则:
- 1与5可以一起写: 1[3,8][0-9]
- 第二种: 14[5,7]
- 第三种: 15[^4]
- 第四种: 17[3,5-8]
- 合并为:
^((1[3,8][0-9])|(14[5,7])|(15[^4])|(17[3,5-8]))\d{8}$
- 注意:\d代表数字,如果要写入 java 代码,则需要多加一条 \ 来转义。如果不想写转义因为\d等价于[0-9]所以也可以换为:
^((1[3,8][0-9])|(14[5,7])|(15[^4])|(17[3,5-8]))[0-9]{8}$
Java 代码:
1 2 3 4 5 6 7 |
public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException { String regExp = "^((1[3,8][0-9])|(14[5,7])|(15[^4])|(17[3,5-8]))\\d{8}$"; //String regExp = "^((1[3,8][0-9])|(14[5,7])|(15[^4])|(17[3,5-8]))[0-9]{8}$"; Pattern p = Pattern.compile(regExp); Matcher m = p.matcher(str); return m.matches(); } |
占用端口进程
我们用 Linux 命令获取占用 22 端口信息如下:
1 2 3 |
[root@vm]# netstat -tnlp | grep ':22 ' tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 21392/sshd tcp6 0 0 :::22 :::* LISTEN 21392/sshd |
只需要用 Python 中 commands 包执行对应命令,取得第一行结果即可得到字符串,我们直接使用该字符用正则提出进程名:
1 2 3 4 |
tcp_str = "tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 21392/sshd" reg_p = re.compile(r'.+ (\d+)/(\w+)') m = reg_p.match(tcp_str) ps_str = m.group(2) # 0 为原字符串,1为进程ID,2为进程名,这里为 sshd |
获取磁盘挂载信息
fdisk 命令
获取插入主机的所有磁盘 fdisk
命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[root@vm]# fdisk -l Disk /dev/vda: 42.9 GB, 42949672960 bytes, 83886080 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos Disk identifier: 0x0008b9e9 Device Boot Start End Blocks Id System /dev/vda1 * 2048 1026047 512000 83 Linux /dev/vda2 1026048 83886079 41430016 8e Linux LVM Disk /dev/vdb: 107.4 GB, 107374182400 bytes, 209715200 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mapper/centos-root: 40.2 GB, 40227569664 bytes, 78569472 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/mapper/centos-swap: 2147 MB, 2147483648 bytes, 4194304 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes |
我们只需要 /dev/vdx
这样的信息,因此需要过滤:
1 2 3 |
[root@vm]# fdisk -l | egrep '^Disk /dev/[a-z]d[a-z]' | awk -F: '{print $1}' | awk '{print $2}' /dev/vda /dev/vdb |
其中 egrep
是选取符合的行如下:
1 2 3 |
[root@vm]# fdisk -l | egrep '^Disk /dev/[a-z]d[a-z]' Disk /dev/vda: 42.9 GB, 42949672960 bytes, 83886080 sectors Disk /dev/vdb: 107.4 GB, 107374182400 bytes, 209715200 sectors |
后面两个 awk
则不断 split 字符串选取出最终的字符。
df 命令
上面的 fdisk
是获取所有的磁盘信息,包括已经挂载以及未挂载的磁盘,而 df
则获取仅仅挂载的信息,这样对于企业中的监控获取未挂载的磁盘,则只需用 fdisk
结果减 df
的结果,这里只介绍用 df
获取磁盘信息:
1 2 3 4 5 6 7 8 9 10 |
[root@vm]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/centos-root 38G 6.5G 32G 18% / devtmpfs 3.9G 0 3.9G 0% /dev tmpfs 3.9G 0 3.9G 0% /dev/shm tmpfs 3.9G 401M 3.5G 11% /run tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup /dev/vda1 497M 150M 348M 31% /boot /dev/vdb 99G 61M 94G 1% /data tmpfs 783M 0 783M 0% /run/user/0 |
我们也只需要 /dev/vdx
这样的信息:
1 2 3 |
[root@vm]# df -Th | /usr/bin/egrep '^/dev/[a-z]d[a-z]\d*' | awk '{print $1}' /dev/vda1 /dev/vdb |
/proc/partitions 文件
这个文件也记录了 Centos 系统的磁盘挂载信息,与 fdisk 命令的结果一致,但是用文件搜索方式比通过 commands 包调用 fdisk 命令效率更高,因此,推荐用此方式来查系统挂载信息:
1 2 3 |
[root@vm]# cat /proc/partitions | egrep ' [a-z]d[a-z]+$' | awk '{print $4}' vda vdb |
/proc/mounts 文件
这个文件则是与 df
命令相似,只记录已经挂载的磁盘信息,并且效率高于 df
命令:
1 2 3 |
[root@vm]# cat /proc/mounts | egrep '^/dev/[a-z]d[a-z]+\d*' /dev/vda1 /boot xfs rw,relatime,attr2,inode64,noquota 0 0 /dev/vdb /data ext4 rw,relatime,data=ordered 0 0 |
这个先查询出行,再用 awk
对行进行截取,这个我就不写了,自己大家可以 awk
。