1. 正则表达式——简介
字符串在计算机中是最为广泛的处理对象(html网页,URL,IP,名称,密码,邮箱...),字符串的组合形式非常多样化。
????????如:
? ? ????????数字字符串: 由任意多个0~9组成的
? ? ????????email邮箱字符串
? ????????? IP地址字符串
? ? ????????网址
? ????????? ...
这些字符串都是我们进行程序设计的时候需要处理的数据,现在就有一个问题:
? ? ? ? 计算机要处理这些字符串,首先要使用某一种方式(能够被全世界所有程序员认可的一种规则)去描述这些要处理的字符串
? ? ? ? 如:
? ? ? ? ????????如果要提取一段字符串中的IP地址,是不是就需要一个"规则"来描述IP地址
? ? ? ????????? 如果符合这个"规则"的就认为它是IP地址
? ? ? ? ????????============>
? ? ? ? ????????描述字符串规则的一种语法(如何使用程序语言去描述一个符合特定规则的字符串)
? ? ? ? ????????正则表达式 ?Regular ?Expression
2. 正则表达式是什么
正则表达式本身也是一个字符串,只不过是用来描述某种"规则字符串"的字符串
脱离了具体语言的一些限制,被大多数程序语言认可,并且现在大部分的程序设计语言都支持正则表达式
? ? ? ? 可以使用一些"规则"去描述一些特定的字符串
? ? ? ? ????????perl
? ? ? ? ????????python
? ? ? ? ????????java
? ? ? ????????? php
? ? ? ? ????????c/c++
? ? ? ? ????????C#
? ? ? ????????? ...
每一种语言实现正则表达式的时候规则略有不同(支持程度不相同)
?=======>正则表达式的流派 ? ?
https://blog.csdn.net/zjc156m/article/details/50773149
?? ??? ?基本的正则表达式(Basic Regular Expression 又叫 Basic RegEx ?简称 BREs) ? ?<----
?? ??? ?扩展的正则表达式(Extended Regular Expression 又叫 Extended RegEx 简称 EREs)
?? ??? ?Perl 的正则表达式(Perl Regular Expression 又叫 Perl RegEx 简称 PREs)知道常用的正则表达式规则
并且知道一些支持正则表达式的文本/字符串处理工具(grep/find/sed/awk)
? ? ? ? grep: 可以查找文件中/目录中符合规则的内容
? ? ? ? find: 可以查找符合规则的文件名
? ? ? ? sed: 可以以行为单位处理文本文件的内容
? ? ? ? awk: 以列为单位处理文本文件的内容
3. 正则表达式中常见的规则
正则表达式是描述某一种"规则字符串"的字符串
?????????如:
? ???????????????十进制的数字字符串 ?[0-9]+
? ? ? ? ? ? ? ? ? ? [0-9]+ ?是形容"十进制数字字符串"的规则
? ? ? ? ? ? ? ? ? ? 规则也叫做模式------->是形容"十进制数字字符串"的模式正则表达式也叫做"匹配模式(pattern)",由一组特殊含义的字符串组成,通常用来匹配和替换文本
正则表达式中的字符,分为两种:
- 普通字符? ??只代表自己本身含义的字符(没有任何的特殊意义)
- 元字符? ? ? ?由特殊含义的字符(不代表本身),如果要让他代表本身,需要加转义字符"\"
正则表达式中常见的元字符(需要记忆)
. ? ? ? ?匹配任意的单个字符
????????????????"m.n" ?查找以m开头,中间有一个任意的字符,以n结尾的字符串? ? ? ? ? ? ? ??"m..n"?查找以m开头,中间有两个任意的字符,以n结尾的字符串
? ? ? ? ?? ? ? ?"m..n"?查找以m开头,中间有三个任意的字符,以n结尾的字符串
? ? ? ? ? ? ? ??……
[]????????字符组,虽然本身含有两个字符,但是仍然只匹配单个字符,而且能够匹配的字符都? ? ? ? ? ? ? ? ? ? ?都在[]中列举出来了
? ? ? ? ? ?[]仅仅匹配括号内列举出来的一个字符
? ? ? ? ? ?????????如: 表示一个能够组成16进制数字的字符
? ? ? ? ? ? ? ? ? ? ? ? ?????????[0123456789ABCDEFabcdef] // 虽然有这么长,但是只表示一个字符? ? ? ? ? ? ? ? ? ? ?????grep -nar [abc]?
? ? ? ? ? ? ? ? ? ? ?????????????查找a或者b或者c
? ? ? ? ? ? ? ? ? ? ???????grep -nar "[abc][012345]"
? ? ? ? ? ? ? ? ? ? ?????????????a0 a1 a2 a3 a4 a5?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? b0 b1 b2 b3 b4 b5
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? c0 c1 c2 c3 c4 c5[] 内部也有一个元字符 ?-
? ? ? ? - 在中括号内部用于连接ASCII码连续的数字字符
? ? ? ? ? ? ? 如: 表示一个能够组成16进制数字的字符
? ? ? ? ? ? ? ? ? ? [0123456789ABCDEFabcdef] ? ?// 虽然有这么长,但是只表示一个字符
? ? ? ? ? ? ? ? ? ? =======>?? [0-9A-Fa-f]?? ? ? ? ? ? ? ? ? ? grep -nar "[abc][012345]"?======> ?grep -nar "[a-c][0-5]"
[^] 排除字符组,匹配单个字符,匹配除了[]内部列举出来的所有单个字符
????????如: 非十进制数字字符? ??[^0-9]
?\d? ?digital? ?匹配单个的十进制数字字符? ?? \d -------> [0-9]
? ? ? ? ? ? ? ? ?\D? ?匹配单个的非十进制数字字符? ??? \D -------> ? [^0-9]
? ? ? ? ? ? ? ??\w? ?word? ??匹配单个字母和数字, _? ??\w------>[a-zA-Z0-9_]
? ? ? ? ? ??
\W? ?匹配单个非字母和数字, _? ? ? ? ?\W------>[^a-zA-Z0-9_]
? ? ? ? ? ? ? ? ??\s? ? 匹配任意的空白符号(回车,换行,空格,tab)? ? ? ?\s ----->[\f\n\t\r\b\v]? ??
? ? ? ? ? ? ? ? ?
\S ?匹配任意的非空白符? ? ?? \S----->[^\f\n\t\r\b\v]
? ? ? ? ? ? ? ??
+? ?匹配一个或者多个先前字符(模式)
? ? ?????????如:????????09+ ? ? // +的前面是一个9 ----->字符?
? ? ? ? ? ? ? ? ? ? ? ? ? ????????09
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 099
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0999
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 09999
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .....
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? [0-9]+ ? // +的前面是一个模式 ----->规则?
? ? ? ? ? ? ? ? ? ? ? ? ? ????????匹配一个或者多个数字
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [0-9]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [0-9][0-9]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [0-9][0-9][0-9]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [0-9][0-9][0-9][0-9]
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .....* ? 匹配0个或者多个先前字符(模式)
?????????????如:????????09* ? ? // *的前面是一个9 ----->字符?
? ? ? ? ? ? ? ? ? ? ? ? ? ????????0
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 09
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 099
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0999
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 09999
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .....
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? [0-9]* ? // *的前面是一个模式 ----->规则?
? ? ? ? ? ? ? ? ? ? ? ? ? ????????空字符串
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [0-9]
? ? ? ? ? ? ? ? ? ? ? ? ?????????[0-9][0-9]
? ? ? ? ? ? ? ? ? ? ? ? ?????????[0-9][0-9][0-9]
? ? ? ? ? ? ? ? ? ? ? ? ?????????[0-9][0-9][0-9][0-9]
? ? ? ? ? ? ? ? ? ? ? ? ?????????..... ???? ? 匹配0个或者1个先前字符(模式)
? ? ? ????????如:? ?09? ? ?// ?的前面是一个9 ----->字符?
? ? ? ? ? ? ? ????????????????0
? ? ? ? ? ? ? ? ????????? ? ? 09
? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ????????? [0-9]? ? // ?的前面是一个模式 ----->规则?
? ? ? ? ? ? ????????? ????????空白
? ? ? ? ? ? ????????? ? ? ? ? 0
? ? ? ? ? ? ????????? ? ? ? ? 1
? ? ? ? ? ? ? ????????? ? ? ? 2
? ? ? ? ? ? ? ????????? ? ? ? 3
? ? ? ? ? ? ????????? ? ? ? ? ...? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 9
{数字}? ? 匹配固定数量的先前模式
??????????????????????如:????????9{3}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????999? ? ? ? ? ? ? ? ? ? ? ? ???????????[0-9]{3}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????000
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????001
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????...
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?999
? ? ? ? ? ??
{最小数量,最大数量}? ? ? 匹配至少最小数量,至多最大数量的先前模式
????????如:????????9{1,3}
? ? ? ? ? ? ? ? ?????????????9
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?99
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?999? ? ? ? ? ? ? ? ? ? ?[0-9]{1,3}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0 ?1 2 3 4 5 .... 9
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?00 01 02 .... 99
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?000 001 002 003 .....999
? ? ? ? ? ??
{最小数量,}? ? 匹配至少最小数量,至多无限制的先前模式????????如:????????abc{1,}
? ? ? ? ? ? ? ? ? ? ?????????abc?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?abcc?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?abccc?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?abcccc
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?....
? ? ? ? ? ??
() ? ? ?把括号内的东西当成一个整体(子模式)
? ? ? ? ? ? ? ? ?如:? ? ??? (abc){1,}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????abc?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? abcabc?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? abcabcabc
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .....
? ? ? ? ? ??
(|) ? ? 括号内部的内容多选1
? ? ? ? ? ? ? ? 如:????????(abc|123){2}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????abcabc?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?123123
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?abc123
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?123abc\ ? ? ? 转义字符,?\+元字符,表示元字符本身
????????????????如:????????\+ ?表示查找+? ? ? ? ? ? ? ? ? ? ?????????????????\+{3} ??
主要使用正则表达式的地方是shell脚本或者其他的一些字符串文本处理工具(grep,find,awk,sed)
标准的C语言对正则表达式有一定的支持
4. 练习
(1)描述一个小于2^32的十六进制的数字字符串
? ? ? ? 0x0
? ? ? ? 0x1
? ? ? ? ....
? ? ? ? 0xffffffff ??
? ? ? ? -------->
? ? ? ? 0[xX][0-9a-fA-F]{1,8}(2)如何描述一个IP地址字符串呢?? ? ?IP: ?1~255.0~255.0~255.0~255?
5. 标准的C库对正则表达式的支持
在C语言代码中也可以使用正则表达式描述或者匹配规则字符串
例子:
????????写一个代码,找出一个普通字符串中所有的IP地址
正则表达式描述IP地址:?
????????(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])
?一组函数? ?regcomp? ?regexec? regerror
NAME regcomp, regexec, regerror, regfree - POSIX regex functions SYNOPSIS #include <sys/types.h> #include <regex.h>
regcomp: 是用来编译正则表达式字符串的 正则表达式本身也是一个字符串,需要把这个字符串转换成一个能够表示正则表达式规则的类型(regex_t) regex_t类型的变量就可以表示一个编译好的正则表达式 原始的正则表达式------->regex_t类型的变量 int regcomp(regex_t *preg, const char *regex, int cflags); preg: 指针,指向一个可用的空间,用来保存编译好的正则表达式的 regex: 指针,指向要编译的正则表达式原始字符串 cflags: 编译标志,使用位域实现(整数中的某些位表示特定的功能) REG_EXTENDED:使用扩展的正则表达式语法编译这个规则 REG_ICASE:ignore case 忽略大小写 REG_NOSUB:不包含子模式 如果在编译的时候,需要使用扩展的正则表达式语法并且需要忽略大小写 REG_EXTENDED | REG_ICASE 待查找字符串: "abc192.168.31.abcabc45.123.168.31abcabcxxxx192.168.31.123xxxx01.199.10.1" 正则表达式规则: (1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) 目标是IP地址,一般认为是总模式(最终的查找目的) 192.168.31.123 [44,58) 用小括号括起来的叫做子模式,上面的规则中有4个子模式 192 第1个子模式 168 第2个子模式 31 第3个子模式 123 第4个子模式 返回值: 编译成功返回0 编译失败返回一个错误码,这个错误码表示一个失败原因,需要使用regerror这个函数去解析
regerror是用来把regcomp/regexec执行返回的错误码,转换成对应的错误字符串的 size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); errcode: 你要转换的错误码,是regcomp/regexec失败时的返回值 preg: 编译好的正则表达式地址 errbuf: 指针,指向一段可用的空间,用来保存转换后的错误信息字符串的 errbuf_size: errbuf指向的可用空间的大小,防止出现内存越界的错误 返回值: 返回填充到errbuf这一段空间中的错误字符串的长度
regexec是用来在string指向的字符串中,查找preg指向的正则表达式规则 匹配结果使用regmatch_t类型来描述,表示目标字符串(IP)在母串中的位置 typedef struct { regoff_t rm_so; // 匹配的起始偏移量 regoff_t rm_eo; // 匹配的终止偏移量 } regmatch_t; // 用来说明匹配的目标在母串中的具体位置 int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); preg:需要匹配的正则表达式(经过regcomp编译过的) string:原始的等待匹配的母字符串,待查找字符串 nmatch:正则表达式中有多少个匹配模式(总模式数量 + 子模式数量) pmatch:保存匹配到的结果的位置(数组) pmatch的大小至少为nmatch 每一个模式都需要使用一个regmatch_t的数据类型去描述位置 总共有多少个模式就有多少个regmatch_t eflags:匹配标志,是否匹配行首或者行尾(一般为0) 返回值: 成功匹配到返回0 如果失败返回REG_NOMATCH
?如果一个待匹配的字符串中有多个结果------>循环多次匹配
void regfree(regex_t *preg); // 用来释放preg这个数据中的空间
代码实现:
#include <stdio.h> #include <sys/types.h> #include <regex.h> // 待查找的目标字符串 char *str = "abc192.168.31.abcabc45.123.168.31abcabcxxxx192.168.31.123xxxx01.199.01.1"; // 使用正则表达式描述你需要查找的规则 // 在C语言的字符中,\本身就是一个转义字符 \.-------> \\. char *reg = "(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])"; int main() { // 转换原始正则表达式--->regex_t regex_t reg_t; int res = regcomp(®_t, reg, REG_EXTENDED | REG_ICASE); if (res != 0) { printf("regcomp failed!\n"); // 可以使用regerror解析失败的原因 char buf[1024] = {0}; regerror(res, ®_t, buf, 1024); printf("buf:%s\n", buf); return -1; } printf("regcomp success!\n"); // 执行转换之后的正则表达式规则(使用正则表达式规则去待查找字符串中做匹配) regmatch_t pmatch[5] = {0}; int offset = 0; while (1) { res = regexec(®_t, str+offset, 5,pmatch,0); if (res == 0) { // 匹配到了字符串,打印结果 printf("找到了一个结果:\n"); for(int i = 0; i < 5; i++) { printf("[%d,%d)\n", pmatch[i].rm_so + offset, pmatch[i].rm_eo + offset); } offset += pmatch[0].rm_eo; } else if (res == REG_NOMATCH) { printf("REG_NOMATCH\n"); break; } else { printf("regcomp failed!\n"); // 可以使用regerror解析失败的原因 char buf[1024] = {0}; regerror(res, ®_t, buf,1024); printf("buf:%s\n", buf); return -1; } } regfree(®_t); return 0; }