0. 问题引入
字符串是计算机应用中最为广泛的处理对象之一
如: http、代码 ==
并且字符串的组合规则形式多样化,比如:
数字字符串
email地址字符串 112223355@qq.com
IP地址字符串 172.110.0.1
这些都是我们程序设计需要处理的对象,现在的问题是:
计算机要处理这些字符串,首先要用某种语言(或
表达式,数据类型等等)去描述这些字符串的规则。
=> 正则表达式 Regular Expression
1. 正则表达式
是什么玩意儿呢?
正则表达式是用来描述某种规则字符串的表达式。
脱离了具体语言的一些规则,但是现在大多数程序设计语言
都实现了或者支持正则表达式;
如:
C/C++
python
java
C#
......
但是每种语言中实现正则表达式的规则略有不同。
2. 正则表达式大的规则
正则表达式是描述某种规则字符串的表达式。
如:
[0-9]+
十进制数字字符串
正则表达式也叫做 匹配模式(pattern),它是由一组特定含义的字符串组成,
通常用于匹配和替换文件。
在正则表达式中的字符,分为两种:
(1) 普通字符串 : 只代表自己本身含义的字符
(2) 元字符 : 有特殊含义(不代表自己)的字符
正则表达式中的元字符:
. 匹配任意单个字符
[] 字符组。虽然由多个字符构成,但它任然只匹配单个字符,
而字符组能够匹配的单个字符都在[]内列举出来啦。
[]仅仅匹配括号内的单个字符!!!
例子: 匹配一个能够组成十六进制数的字符
[0123456789abcdefABCDEF]
注意:
[]字符组内部有一个元字符 -
-在[]内用于链接ASCII连续的字符
=> [0-9a-fA-F]
例子:
描述一个可以作为C语言标识符的字符
[0-9a-zA-Z_]
[^] 排除字符组。匹配单个字符,匹配除[]内以外的所有单个字符
如:
非十进制数字字符
[^0-9]
\d digtial
匹配单个十进制数字字符
\d <=> [0-9]
\D Digtial
匹配单个非十进制数字字符
\D <=> [^0-9]
\w word 匹配单个单词中能出现的字符
匹配字母、数字、_
\w <=> [a-zA-Z0-9_]
\W 匹配单个非 字母、数字、_
\W <=> [^a-zA-Z0-9_]
\s 匹配单个空白符
\s <=> [\f\n\t\r\v]
\f 换页
\n 换行
\r 回车
\t 制表
\v 垂直制表
\S 匹配单个非空白符
\S <=> [^\f\n\t\r\v]
例子: 如果是排除字符组,'^'需要放置前面
[a-z^0-9]
匹配单个字符 a-z 0-9 ^
-------------------------------------------
匹配多个字符:
+ 匹配一个或多个先前的字符(或模式)
如:
09+
=>
09
099
0999
09999
....
099.....9
0[0-9]+
=>
0[0-9]
0[0-9][0-9]
0[0-9][0-9][0-9]
.......
0[0-9][0-9].....[0-9]
* 匹配0个或多个先前字符(或模式)
如:
09*
=>
0
09
099
0999
.....
0999....99
[0-9]*
=>
"" 空串
[0-9]
[0-9][0-9]
......
[0-9][0-9]....[0-9]
? 匹配0个或1个先前字符(或模式)
如:
09?
=>
0
09
[0-9]?
=>
"" 空串
0
1
2
...
9
{数字} 匹配固定数目的字符(或模式)
如:
88[0-9]{3}
<=> 88[0-9][0-9][0-9]
09{3}
<=> 0999
{最小数目, 最大数目}
匹配至少 “最小数目”,到至多“最大数目”先前的字符(或模式)
如:
8{1,3}
=>
8
88
888
{最小数目, }
匹配至少“最小数目”,上不封顶 的先前字符(或模式)
如:
abc{1, }
=>
abc
abcc
....
abccc..cc
() 作为一个整体,子模式
如:
(abc){1,3}
=>
abc
abcabc
abcabcabc
(|) 二选一
如:
(abc|123){2}
<=> (abc|123)(abc|123)
abcabc
abc123
123abc
123123
转义元字符:
\元字符 => 元字符就不是元字符,就是普通字符啦
如:
\. 代表一个普通字符'.'
\* 代表一个普通字符'*'
\+ 代表一个普通字符'+'
......
3. 正则表达式的使用
grep(egrep) 用来在一个文件(ASCII,字符)中查找一个特定的字符串。
egrep是用扩展的正则表达式去查找!
语法:
grep(egrep) options [正则表达式] files
在files列出的所有文件里面,查找以“正则表达式”所描述的字符串。
options :
-n 显示查找到的字符串所有行号
-E 用扩展的正则表达式
grep -E
=>
egrep
-i ignore在字符串查找时忽略大小写
-i "main"
[mM][aA][iI][nN]
-# 表示同时显示匹配行的上下#行
#表示一个整数值
-c count 打印每个文件里面匹配行的个数
加-c不会显示文件匹配到的内容。
-H 显示文件名
-h 不显示文件名
匹配内容颜色高亮显示
--color=always 总是高亮显示
--color=never 不高亮显示
--color=auto 随意
例子:
egrep -niH -1 "[0-9]+" ./*.sh --color=always
-------------------------------------------------------
find 用来在一个文件系统中查找指定的文件
语法:
find path options
path: 表示搜素路径,指定去文件系统的哪个位置去搜素
options :
-name pattern
指定要查找的文件的名字,可以用通配符
* 代表0个或多个任意字符
? 代表一个任意字符
如:
find ./ -name "*.c"
在当前目录(以及当前目录下面的目录下面...)查找
所有的以.c结尾的文件。
-regex pattern
以正则表达式的方式指定要查找的文件名
注意: 路径也是正则表达式描述的内容
如:
find ./ -regex ".*[ch]" 找所有以c结尾或者h结尾
find ./ -regex ".*\.c" 找所有以.c结尾的文件
-type b|c|d|p|f|l|s 指定要搜素的文件的类型
b: block块设备
c: char 字符设备
d: dir 目录
p: pipe 管道
f: regular file 普通文件
l: link 符号链接 软连接
s: socket 套接字
如: 当前目录下找所有名字以.c结尾的符号链接文件
find ./ -name "*.c" -type l
-size n[cwbKMG]
-size 5
5*512 默认为块
b: 单位为块 a block(512Bytes)
c: 单位为字节
w: work 单位为字 for two-byte
K: 1KB = 1024 Bytes
M: 1MB = 1024 KB
G: 1GB = 1024 MB
如:
find ./ -name "*.c" -size 2c
-perm mode 要查找的文件的权限
permission 权限
mode 有两种写法:
-mode 要求所有 (为1)权限位都要被匹配
如;
-perm -664
待查找的文件权限必须为 110 110 100
/mode 只要匹配一位即可
如:
-perm /111
带查找的文件权限只要有一个可执行的位即可
-newer file
查找比文件file更新的文件
带查找的文件的修改的时间在file这个文件的后面即可。
如:
find ./ -newer 9.sh
-delete
找到即删除
如:
find ./1.txt ./2.txt -delete
find ./xxx/ -delete
-exec command {} \;
每查找到一个文件就执行 command 这个命令,
{} 代表找到的文件的文件名,找到一个文件,就执行一次command
这个命令。
如:
find ./ -name "*.c" -exec ls -l {} \;
-exec command {} +
所有文件查找完成后,再执行command这个命令,
{} + 代表所有查找到的文件的文件名(以空格隔开)
4. 标准C库,对正则表达式的支持
案列:
写一个C语言程序,判断一个字符串是否为IP字符串?
"abc192.168.31.111abcfdsdafh"
void find_ip(const char * str)
{
}
用正则表达式的语法来描述一个正确的IP字符串:
"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
关于C库对正则表达式的支持的AIP函数:
NAME
regcomp, regexec, regerror, regfree - POSIX regex functions
SYNOPSIS
#include <sys/types.h>
#include <regex.h>
regcomp : 用来编译正则表达式
编译好的正则表达式用类型 regex_t 来描述。
"正则表达式"原始字符串 -> regex_t 编译好的正则表达式
1、 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
返回值:
成功返回0
失败返回一个错误码,该错误码需要调用 regerror去解析!
===================================================================================================
待查找的原始字符串: "abc192.168.31.111abcfdsdafh"
以正则表达式去找: "([0-9]{1,3})\\.[0-9]{1,3}\\.([0-9]{1,3})\\.([0-9]{1,3})"
regexec: 用来匹配正则表达式所描述的模式
模式:
总模式 192.168.31.111
[3, 17)
子模式
192 [3, 6)
31 [11,13)
111 [14,17)
匹配的结果用 regmatch_t 来描述,返回的是再木船中匹配到的模式对象
下标范围( [起始下标, 终点下标) )
typedef struct
{
regoff_t rm_so; //start offset 起始偏移量
regoff_t rm_eo; //end offset 终点偏移量
一个模式需要对应一个regmatch_t类型的结构体变量!
例子:
regmatch_t t;
t.rm_so = 3;
t.rm_eo = 17;
[rm_so , rm_eo)
} regmatch_t;
2、int regexec(const regex_t *preg, const char *string, size_t nmatch,regmatch_t pmatch[], int eflags);
@preg : 正则表达式的指针。
@string : 原始的等待匹配的字符串。待查找的字符串
@nmatch : 正则表达式中有多少个模式
总模式(1个) + 子模式个数
@pmatch : 结构体数组
保存匹配到的模式的信息。
nmatch 其实就是结构体数组元素个数!
总共有多少个模式需要匹配,则需要有多少个结构体regmatch_t
@eflags: 标志是否匹配行首或行尾。
一般为0
返回值:
如果成功(匹配到了)返回0
如果失败返回 REG_NOMATCH
=================================================================================================
regerror: 把 regcomp/regexec 运行返回的错误码,转换成相应的错误
字符串信息。
3、size_t regerror(int errcode, const regex_t *preg, char *errbuf,size_t errbuf_size);
@errcode : 错误码。由regcomp/regexec返回的值。
@preg : 编译好的正则表达式
@errbuf : 指向一段内存,用来保存转换后的错误提示信息
@errbuf_size : errbuf的大小。最多能够保存多少个字节信息
返回值:
返回填充到errbuf中的错误提示字符串的长度。
===================================================================================================
4、regfree:用来释放preg指向的空间的。
void regfree(regex_t *preg);