正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。--来自百度百科
在c语言中,用regcomp、regexec、regfree 和regerror处理正则表达式。处理正则表达式分三步:
四个函数的详细解释:
/*
函数说明:Regcomp将正则表达式字符串regex编译成regex_t的形式,后续regexec以此进行搜索。
参数说明:
Preg:一个regex_t结构体指针。
Regex:正则表达式字符串。
Cflags:是下边四个值或者是他们的或(|)运算。
REG_EXTENDED:使用POSIX扩展正则表达式语法解释的正则表达式。如果没有设置,基本POSIX正则表达式语法。
REG_ICASE:忽略字母的大小写。
REG_NOSUB:不存储匹配的结果。
REG_NEWLINE:对换行符进行“特殊照顾”,后边详细说明。
返回值:
0:表示成功编译;
非0:表示编译失败,用regerror查看失败信息
*/
int regcomp(regex_t *preg, const char *regex, int cflags);
/*
函数说明: Regexec用来匹配正则文本。
参数说明:
Preg:由regcomp编译好的regex_t结构体指针,
String:要进行正则匹配的字符串。
Nmatch:regmatch_t结构体数组的大小
Pmatch:regmatch_t结构体数组。用来保存匹配结果的子串位置。
regmatch_t结构体定义如下
typedef struct {
regoff_t rm_so;
regoff_t rm_eo;
} regmatch_t;
rm_so,它的值如果不为-1,表示匹配的最大子串在字符串中的起始偏移量,rm_eo,表示匹配的最大字串在字符串的结束偏移量。
Eflags: REG_NOTBOL和REG_NOTEOL为两个值之一或二者的或(|)运算,稍后会介绍。
返回值:
0:表示成功编译;
非0:表示编译失败,用regerror查看失败信息
*/
int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
/*
函数说明:用来释放regcomp编译好的内置变量。
参数说明:
Preg:由regcomp编译好的regex_t结构体指针。
*/
void regfree(regex_t *preg);
/*
函数说明:Regcomp,regexec出错时,会返回error code并且为非0,此时就可以用regerror得到错误信息。
参数说明:
Errcode:Regcomp,regexec出错时的返回值
Preg:经过Regcomp编译的regex_t结构体指针。
Errbuf:错误信息放置的位置。
errbuf_size:错误信息buff的大小。
*/
size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
好现在开始写一个简单的正则匹配小程序。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
char ebuff[256];
int ret;
int cflags;
regex_t reg;
cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
char *test_str = "Hello World";
char *reg_str = "H.*";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "%s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "%s\n", ebuff);
goto end;
}
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "result is:\n%s\n", ebuff);
end:
regfree(®);
return 0;
}
编译,输出结果:
[[email protected] regex]# ./test
result is:
Success
匹配成功。
如果我想保留匹配的结果怎么操作?那就得用到 regmatch_t 结构体了。重新改写上边代码,这时就不能用REG_NOSUB选项了,代码如下:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
int i;
char ebuff[256];
int ret;
int cflags;
regex_t reg;
regmatch_t rm[5];
char *part_str = NULL;
cflags = REG_EXTENDED | REG_ICASE;
char *test_str = "Hello World";
char *reg_str = "e(.*)o";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "%s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 5, rm, 0);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "%s\n", ebuff);
goto end;
}
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "result is:\n%s\n\n", ebuff);
for (i=0; i<5; i++)
{
if (rm[i].rm_so > -1)
{
part_str = strndup(test_str+rm[i].rm_so, rm[i].rm_eo-rm[i].rm_so);
fprintf(stderr, "%s\n", part_str);
free(part_str);
part_str = NULL;
}
}
end:
regfree(®);
return 0;
}
编译,输出结果:
[[email protected] regex]# ./test
result is:
Success
ello Wo
llo W
咦??????我明明只要一个匹配结果,为什么会打印两个出来呢???????
原来regmatch_t数组的第一个元素是有特殊意义的:它是用来保存整个正则表达式能匹配的最大子串的起始和结束偏移量。所以我们在设置regmatch_t数组个数的时候一定要记住,它的个数是最大保留结果数+1。
好了,基本的正则运用到此为止了,现在要开始讲讲REG_NEWLINE、REG_NOTBOL和REG_NOTEOL。很多人对这三个参数有所迷惑。我也是,昨天有人问问题,就把自己错误的理解告诉了别人,然后被大神一顿鄙视。我一直认为如果想用^和$这两个匹配模式一定要用到REG_NEWLINE这个参数,其实不然。
首先看下man page对REG_NEWLINE的说明:
REG_NEWLINE
Match-any-character operators don’t match a newline.
A non-matching list ([^...]) not containing a newline does not match a newline.
Match-beginning-of-line operator (^) matches the empty string immediately after a newline, regardless of whether eflags, the execution flags of regexec(), contains REG_NOTBOL.
Match-end-of-line operator ($) matches the empty string immediately before a newline, regardless of whether eflags contains REG_NOTEOL.
我英文不好,google翻译之。。
REG_NEWLINE
1.匹配任何字符的运算符(比如.)不匹配换行('\n');
2.非匹配列表([^...])不包含一个换行符不匹配一个换行符;
3.匹配开始运算符(^)遇到空字符串立即换行,不论在执行regexec()时,eflags是否设置了REG_NOTBOL;
4.匹配结束运算符($)遇到空字符串立即换行,不论在执行regexec()时,eflags是否设置了REG_NOTEOL;
不明白说的是什么,程序测之。。
第一个问题,代码如下:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
int i;
char ebuff[256];
int ret;
int cflags;
regex_t reg;
cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
char *test_str = "Hello World\n";
char *reg_str = "Hello World.";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "1. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "2. %s\n", ebuff);
cflags |= REG_NEWLINE;
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "3. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "4. %s\n", ebuff);
end:
regfree(®);
return 0;
}
编译,运行结果如下:
[[email protected] regex]# ./test
2. Success
4. No match
结果很明显:没有加入REG_NEWLINE的匹配成功,加入的匹配不成功。就是说不加入REG_NEWLINE,任意匹配字符(.)包含'\n',加入则不包含'\n'。
第二个问题,代码如下:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
int i;
char ebuff[256];
int ret;
int cflags;
regex_t reg;
cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
char *test_str = "Hello\nWorld";
char *reg_str = "Hello[^ ]";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "1. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "2. %s\n", ebuff);
cflags |= REG_NEWLINE;
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "3. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "4. %s\n", ebuff);
end:
regfree(®);
return 0;
}
编译,运行结果如下:
[[email protected] regex]# ./test
2. Success
4. No match
结果说明:不加入REG_NEWLINE,在一个不包含'\n'的非列表中,'\n'是不被认作空白符,加入则'\n'是被认作空白符。
第三个问题,代码如下:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
int i;
char ebuff[256];
int ret;
int cflags;
regex_t reg;
cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
char *test_str = "\nHello World";
char *reg_str = "^Hello";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "1. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "2. %s\n", ebuff);
cflags |= REG_NEWLINE;
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "3. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "4. %s\n", ebuff);
end:
regfree(®);
return 0;
}
编译,运行结果如下:
[[email protected] regex]# ./test
2. No match
4. Success
结果说明:不加入REG_NEWLINE,'^'是不忽略'\n'的,加入REG_NEWLINE,'^'是忽略'\n'的。也就是说:不加入REG_NEWLINE,以'\n'开头的字符串是不能用'^'匹配,加入REG_NEWLINE,以'\n'开头的字符串是可以用'^'匹配。
第四个问题,代码如下:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
int i;
char ebuff[256];
int ret;
int cflags;
regex_t reg;
cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
char *test_str = "Hello World\n";
char *reg_str = "d$";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "1. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "2. %s\n", ebuff);
cflags |= REG_NEWLINE;
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "3. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "4. %s\n", ebuff);
end:
regfree(®);
return 0;
}
编译,运行结果如下:
[[email protected] regex]# ./test
2. No match
4. Success
结果说明:不加入REG_NEWLINE,'$'是不忽略'\n'的,加入REG_NEWLINE,'$'是忽略'\n'的。也就是说:不加入REG_NEWLINE,以'\n'结尾的字符串是不能用'$'匹配,加入REG_NEWLINE,以'\n'开头的字符串是可以用'$'匹配。
好,REG_NEWLINE选项测试到此结束。总结下:
对于REG_NEWLINE选项,1.使用任意匹配符(.)时,任意匹配符不会包含'\n';2.对于一个不含有'\n'的非列表,会把'\n'认作空白符。3.对于以'\n'开头或结尾的字符串,会忽略'\n'。使'^'和'$'可以使用。
现在开始说下REG_NOTBOL和REG_NOTEOL,首先看下man page对这两选项的说明:
REG_NOTBOL
The match-beginning-of-line operator always fails to match (but see the compilation flag REG_NEWLINE above) This flag may be used when different portions of a string are passed to regexec() and the beginning of the string should not be interpreted as the beginning of the line.
REG_NOTEOL
The match-end-of-line operator always fails to match (but see the compilation flag REG_NEWLINE above)
继续googling。
REG_NOTBOL
匹配开始操作符(^)会经常匹配失败(但是要考虑REG_NEWLINE),这个标志被用在当一个字符串的不同位置被传入到regexec()时,这个位置不应该被解释为该整个字符串的开始位置。
REG_NOTEOL
匹配结束操作符($)会经常失败(但是要考虑REG_NEWLINE)。(这个标志被用在当一个字符串的不同位置被传入到regexec()时,即使满足匹配结束作符,也不应该被解释为以某字符(串)为结束的)。
好吧,继续测试,第一个问题代码如下:
#define _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
int main (void)
{
int i;
char ebuff[256];
int ret;
int cflags;
regex_t reg;
cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;
char *test_str = "Hello World\n";
char *reg_str = "^e";
ret = regcomp(®, reg_str, cflags);
if (ret)
{
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "1. %s\n", ebuff);
goto end;
}
ret = regexec(®, test_str+1, 0, NULL, 0);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "2. %s\n", ebuff);
ret = regexec(®, test_str+1, 0, NULL, REG_NOTBOL);
regerror(ret, ®, ebuff, 256);
fprintf(stderr, "4. %s\n", ebuff);
end:
regfree(®);
return 0;
}
编译,运行结果如下:
[[email protected] regex]# ./test
2. Success
4. No match
结果说明:不加入REG_NOTBOL,一个字符串的不同位置是可以用'^'进行匹配,加入REG_NOTBOL,则不能进行匹配。
第二个问题,我实在理解不了了,网上介绍的全是没有经过验证的。。。。。。
大家好,这里是笑颜の行方。本篇描述的是 border-image ,即
JDK8在线Api中文手册JDK8在线Api英文手册探究java.io1 I/O 类和接口2 File 类2.1 目录2.2 使用FilenameFilter接口 本篇研究java.io,该包提供了对I/O操作的支持。我们早就知道,如果不访问外部数据,大多数程序就不能完成它们的目标。数据是从输入源获取的。程序的结果被发送到输出目标。在Java中,这些源或目标...
JS部分<script> var layer, form, laypage, index, newindex, laydate; var pageIndex = 1; var pageSize = 1;//页大小10 var total; //总条数 var SearchId = "0"; $(function () { layui.use(['layer', 'f
371.In what state are the datafiles of a tablespace after a TSPITR has been successfully completed?A. The datafiles have an ONLINE status.B. The datafiles have an OFFLINE status.C. The datafiles
PowerBuilder7.0在Internet中的应用(加入日期:2001-6-11)【保存文章至硬盘】【打印文章】【字体:大中小】分享到: 0随着Internet /Intranet的发展和万维网(www)的出现,传统的客户机/服务器方式(c/s)逐渐向浏览器-Web服务器-数据库(bwd)方式过渡。后者与前者相比易学易用,操作性强,可扩充和维护性好。文章主要就Po
[DCC Error] E2161 Error: RLINK32: Error opening file "_____.drf" 程序越做越大了,所有用了包,使用包,一些共用数据,好用多了,不用传来传去的。在一次加入单元时,出现这个错误[DCC Error]...
请帮我理解我的错误.我正在尝试更改.csv文件中的一列.我有.csv文件如下:sku,name,codek1,aaa,886k2,bbb,898k3,ccc,342k4,ddd,503k5,eee,401我想用“sku”列中的“_”符号替换“k”符号.我写了代码:import sysimport pandas as pdimport numpy as npimport datetimedf = p...
解决 SpringBoot 在 JDK8 中 LocalDateTime (反)序列化问题
CSS3 属性选择器 CSS3 属性选择器,在 CSS3 中,追加了三个属性选择器分别为:[att*=val]、[att^=val]和[att$=val],使得属性选择器有了通配符的概念。[att*=val]表示包含。CSS3 结构性伪类选择器,包含伪类选择器和伪元素选择器,在伪元素选择器中包含 first-line(给元素内容第一行增加属性)、first-letter(给元素内容首字母增加属性)...
安卓 iOS 点击的兼容性css兼容性
本文主要向大家介绍了非常实用的java语言自动答题计时计分器,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。该小程序使用java语言编写,让用户计算10以内的加减乘除法,特别适合小学开始学习加减乘除法的学生,能很好地锻炼他们的运算能力,并过计分计时的游戏性质引起学习兴趣!运行该程序会弹出一个窗口,按enter键开始答题,答完再按enter则进行计分和正确性判断,并出下一道题!每轮1...
当前测试条件cad使用2012,Altium Designer 使用 6.9注意事项1 cad存储的格式必须选择cad2000版本的格式,后缀可以是dwg注意事项2 导入时必须先建立一个空的pcb图纸,之后再pcb编辑模式下才可以选择文件菜单下的导入。建议,导入之前对cad图纸进行分层处理,并且命令为适当的名称。其他事项可以参考下面的链接https://wenku.baidu.com/view/5e15a1426c85ec3a87c2c576.htmlhttps:/...