在程序员一生的工作中,遇到的最多的数据就是字符串
字符串里面很有可能有很多的不需要的信息
我们需要从中间挑选出我们需要的
如果循环去写,比较简单的时候问题不大
规则多了,你的工作量会成倍上升的
为了解决这个问题 ---- 正则表达式
正则表达式 --- 一种规则,用于匹配我们需要的字符/字符串
简单一点就是一种匹配规则
字符串的处理通过这个正则表达式会变得简单很多
正则表达式字符分为两种
1 普通字符 -- 只代表这个字符本身
a b c d e f......
2 元字符:有特殊意义的字符
它不代表字符本身的意思,另外赋予它意思了
如:scanf printf里面的%
正则表达式里面的元字符
. : 匹配任意的一个单个字符
[] : 字符组,但是它只代表其中一个
[]里面可能会写很多个字符,但是只代表一个字符
只能有一个字符和[]里面的字符去匹配
挑里面有的去匹配
如:[abcdefg] -> 43720jklrhj423urlkehk23hijka
后面的字符串只有e 和 a才能被匹配
这个[]里面也有一个元字符 -
-:表示从ASCII码开始到ASCII码结束这一节所有的字符
有开始有结束才代表连接,否则就是-自己本身
[A-Z]: 表示 A到Z中间所有的字符,只会匹配其中一个
[a-z]: 匹配一个小写字母
[A-Za-z]:匹配
[0-9]:匹配数字字符
[-9]:这个没有开始,那么-就是它自己
匹配-或者9字符
^ : 排除字符,把它们排除掉
[^0-9] : 排除所有的数字字符,其它的字符都可以和我匹配
[^0-9A-Za-z] : 排除数字字符和字母
字母 数字这些比较特殊,因此会有东西直接表示
\d : 匹配数字字符
\D : 排除数字字符
\w : 匹配数字字母下划线
\W : 排除数字字母下划线
\s : 空白字符
\S : 非空字符
匹配多个字符
+ : 匹配1个或者多个先前字符
[A-Z]+ 匹配长度至少为1的大写字母
[A-Z]
[A-Z][A-Z]
[A-Z][A-Z][A-Z]
[A-Z][A-Z][A-Z][A-Z]
........
dahsjkAbc -> 只有A可以匹配
dhsajkDEf -> DE可以匹配
dasdwqda -> 没有
A
BC
DFG
.....
* :匹配0个或者多个先前字符
[A-Z]*
空的
[A-Z]
[A-Z][A-Z]
[A-Z][A-Z][A-Z]
[A-Z][A-Z][A-Z][A-Z]
........
? : 匹配0个或者1个先前字符
[A-Z]?
空的
[A-Z]
我们也可以指定数量来进行匹配
{数字}
a{3}
aaa
[A-Z]{3}
[A-Z][A-Z][A-Z]
指定数量里面我们也可以给范围
{最小数量,最大数量}
[A-Z]{1,3}
[A-Z]
[A-Z][A-Z]
[A-Z][A-Z][A-Z]
如果没有最大数量表示上不封顶
()被看成是一个整体,这个整体我们叫子模式
(abc){1,3}
abc
abcabc
abcabcabc
abc{1,3} -> 区分
abc
abcc
abccc
(|) 二选一
(abc|123){1,2}
abc
abcabc
abc123
123
123123
123abc
\ 转义字符
\. ->普通的.
\d.c -> 1.c 11c 1cc 2cc 3dc
\d\.c -> 1.c 2.c 3.c
\\ ->普通的\
\* ->普通的*
ipv4 : 用4个字节表示一个ip地址
xxx.xxx.xxx.xxx
192.168.5.250
有一个字符串待匹配
dhasjkdhwq3123.342432.123.34.53.6dashjk.123.234.12.4dhasjk
请你写一个正则表达式来匹配ip地址
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
我在我的系统里面存了一个pxxxxx.c的这么一个文件,我忘记放哪里了,你帮我找一下
xxxxx是数字,我不记得有多少个了
p[0-9]+\.c
c语言支持了正则表达式
NAME
regcomp, regexec, regerror, regfree - POSIX regex functions
SYNOPSIS
#include <sys/types.h>
#include <regex.h>
int regcomp(regex_t *preg, const char *regex, int cflags);
preg:编译好了的正则表达式 --- 就是它能看得懂的字节码
这个玩意儿是一个地址
regex:你编辑的正则表达式,是一个字符串
如:"p[0-9]+\.c"
cflags: 标志 ,用位域实现的
REG_EXTENDED : 扩展的正则表达式,一般都带上这个标志
REG_ICASE : 忽略大小写
REG_NOSUB : 忽略子模式
REG_EXTENDED | REG_ICASE 用扩展的正则表达式并且忽略大小写
成功返回0,失败返回错误码
//运行我们的正则表达式
int regexec(const regex_t *preg, const char *string, size_t nmatch,
regmatch_t pmatch[], int eflags);
preg:编译好了的正则表达式
string:待匹配字符串
nmatch:你有多少个模式 1 + n,一般n <= 实际子模式数
总模式(1) + 子模式(n)
"ds(ajh)(kd)wh(jk)"
pmatch:匹配的信息,也就是匹配的结果
它是一个数组
pmatch = malloc(sizeof(regmatch_t) * nmatch)
第一个元素为总模式
后面的为子模式
typedef struct {
regoff_t rm_so;//start 开始 待匹配字符串的下标
regoff_t rm_eo;//end 结束 待匹配字符串的下标
} regmatch_t;
eflags:一个标志
一般给0
返回值:
成功返回0,你可能会有后续继续的匹配
失败返回 REG_NOMATCH
size_t regerror(int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size);
errcode:错误码
preg:编译了的正则表达式
errbuf:存放解析好了的错误信息
errbuf_size:你给errbuf的最大存储空间
成功返回实际写入errbuf里面的字节数
void regfree(regex_t *preg);
释放preg
//心中有的数 如果是正则表达式是有问题的为1 如果是其它的表示为2 成功是0
int regerror(int errcode, const regex_t *preg, char *errbuf,
size_t errbuf_size)
{
int len = 0;
switch(errcode)
{
case 0:
len = strlen("success") < errbuf_size ? strlen("success") : errbuf_size;
strncpy(errbuf,"success",len);
return len;
case 1:
len = strlen("zheng ze biao da shi you wen ti") < errbuf_size ? strlen("zheng ze biao da shi you wen ti") : errbuf_size;
strncpy(errbuf,"heng ze biao da shi you wen ti",len);
return len;
case 2:
len = strlen("other") < errbuf_size ? strlen("other") : errbuf_size;
strncpy(errbuf,"other",len);
return len;
default:
return -1;
}
}
#include <sys/types.h>
#include <regex.h>
#include <stdio.h>
#include <string.h>
//我们挑网址出来 (www){1}\.[A-Za-z0-9]+\.(com){1}
#define REGEXSTRING "(www){1}\\.[A-Za-z0-9]+\\.(com){1}"
const char * const str = "dsahejkdwqhdsaww.sadhjkdhwww.dashjd.www.baidu.com\
dashjkdhwqjww.baidu.cmwww.hehe.comasdwqwww.123123.comshadjkwqhk";
int main()
{
//编译我们的正则表达式
//regex_t * preg = (regex_t *)malloc(sizeof(regex_t));//空间是在堆上面开的 搞完要释放的
regex_t preg;//在栈上面开的 代码块弄完自动释放
int r = regcomp(&preg,REGEXSTRING,REG_EXTENDED);
char buf[1024] = {0};
if(r != 0)//错了
{
//解析错误信息
int l = regerror(r,&preg,buf,1023);
if(l > 0)//解析错误成功
{
//最好补个\0
buf[l] = 0;
printf("regcomp error:%s\n",buf);
return -1;
}
printf("不知道什么错误\n");
return -2;
}
//执行正则表达式
//返回值如果为0 说明后面还有可能有未匹配到的
const char * ptr = str;
regmatch_t pmatch[3];//存放我们的结果
while(1)
{
r = regexec(&preg,ptr,3,pmatch,0);
if(r != 0)
{
break;
}
//匹配成功
for(int i = 0;i < 3;i++)
{
printf("[%ld,%ld) -> ",pmatch[i].rm_so + ptr - str,pmatch[i].rm_eo + ptr - str);
strncpy(buf,ptr + pmatch[i].rm_so,pmatch[i].rm_eo - pmatch[i].rm_so);
buf[pmatch[i].rm_eo - pmatch[i].rm_so] = 0;//补\0
if(i == 0)
{
printf("总模式:%s\n",buf);
}
else
{
printf("子模式:%s\n",buf);
}
}
ptr += pmatch[0].rm_eo;//将匹配过的字符串给跳过
}
regfree(&preg);
return 0;
}
//有用正则表达式的命令
find -> 查找
find [path] [options]
path:你要查找的路径
不给默认当前路径
options:
-name -> 指定你要查找的名字
里面有两个通配符可以使用
* -> 所有的
? -> 一个字符
find ./ -name "*.c" -> 在当前路径下面查找所有的.c文件
-regex -> 用正则表达式来查
查当前文件夹下面所有的数字.c文件
find ./ -regex "\d+\.c"
-type 指定要查找的文件的类型
b block (buffered) special 块设备
c character (unbuffered) special 字符设备
d directory 文件夹
p named pipe (FIFO) 有名管道
f regular file 普通文件
l symbolic link; this is never true if the -L option or the
-follow option is in effect, unless the symbolic link is
broken. If you want to search for symbolic links when -L
is in effect, use -xtype.
s socket
D door (Solaris)
-size 指定大小
默认以块为单位
-size 5
实际查找文件大小为 5 * 512字节
`b' for 512-byte blocks (this is the default if no suffix is
used) 块
`c' for bytes 字节
`w' for two-byte words 两个字节
`k' for Kibibytes (KiB, units of 1024 bytes)
`M' for Mebibytes (MiB, units of 1024 * 1024 = 1048576 bytes)
`G' for Gibibytes (GiB, units of 1024 * 1024 * 1024 =
1073741824 bytes)
-delete 找到及删除
-exec commod {} \;
找到及执行 commod
{}为执行结果的占位符
find ./ -name "*.h" -exec tar -jcvf 1.tar.bz2 {} \;
找到当前路径下面所有的.h文件,然后将其压缩为 1.tar.bz2
grep:在一个文件里面查找对应的字符串
grep [OPTIONS] PATTERN [FILE...]
FILE你的待匹配的文件路径名
PATTERN : 正则表达式
OPTIONS:
-n 显示查找到的字符串所在行
-E 用扩展的正则表达式
-i 忽略大小写
-# 同时显示匹配的上下#行
-c 打印每个文件匹配行的个数
-H 显示文件名
-h 不显示文件名