C语言使用正则表达式

C语言使用正则表达式目录C语言中的正则表达式使用C语言中的正则表达式使用  正则表达式,又称正规表示法、常规表示法(英语:RegularExpression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式是使用单个字符串来描述、匹配一系列符合某…

大家好,又见面了,我是你们的朋友全栈君。

C语言中的正则表达式使用

  正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。–来自百度百科

  在c语言中,用regcomp、regexec、regfree 和regerror处理正则表达式。处理正则表达式分三步:

  1. 编译正则表达式,regcomp;
  2. 匹配正则表达式,regexec;
  3. 释放正则表达式,regfree。

四个函数的详细解释:

/* 函数说明: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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "%s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str, 0, NULL, 0);
    if (ret)
    {
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "%s\n", ebuff);
        goto end;
    }   

    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "result is:\n%s\n", ebuff);

end:
    regfree(&reg);

    return 0;
}

编译,输出结果:

[root@zxy 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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "%s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str, 5, rm, 0); 
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "%s\n", ebuff);
        goto end;
    }

    regerror(ret, &reg, 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(&reg);

    return 0;
}

编译,输出结果:

[root@zxy regex]# ./test 
result is:
Success

ello Wo
llo W

  咦??????我明明只要一个匹配结果,为什么会打印两个出来呢???????

  原来regmatch_t数组的第一个元素是有特殊意义的:它是用来保存整个正则表达式能匹配的最大子串的起始和结束偏移量。所以我们在设置regmatch_t数组个数的时候一定要记住,它的个数是最大保留结果数+1。

  好了,基本的正则运用到此为止了,现在要开始讲讲REG_NEWLINEREG_NOTBOLREG_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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "1. %s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str, 0, NULL, 0); 
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "2. %s\n", ebuff);

    cflags |= REG_NEWLINE;

    ret = regcomp(&reg, reg_str, cflags);
    if (ret)
    {
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "3. %s\n", ebuff);
        goto end;
    }

    ret = regexec(&reg, test_str, 0, NULL, 0);
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "4. %s\n", ebuff);

end:
    regfree(&reg);

    return 0;
}
  编译,运行结果如下:
[root@zxy 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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "1. %s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str, 0, NULL, 0); 
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "2. %s\n", ebuff);

    cflags |= REG_NEWLINE;

    ret = regcomp(&reg, reg_str, cflags);
    if (ret)
    {
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "3. %s\n", ebuff);
        goto end;
    }

    ret = regexec(&reg, test_str, 0, NULL, 0);
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "4. %s\n", ebuff);

end:
    regfree(&reg);

    return 0;
}
编译,运行结果如下:
[root@zxy 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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "1. %s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str, 0, NULL, 0); 
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "2. %s\n", ebuff);

    cflags |= REG_NEWLINE;

    ret = regcomp(&reg, reg_str, cflags);
    if (ret)
    {
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "3. %s\n", ebuff);
        goto end;
    }

    ret = regexec(&reg, test_str, 0, NULL, 0);
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "4. %s\n", ebuff);

end:
    regfree(&reg);

    return 0;
}

编译,运行结果如下:

[root@zxy 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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "1. %s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str, 0, NULL, 0); 
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "2. %s\n", ebuff);

    cflags |= REG_NEWLINE;

    ret = regcomp(&reg, reg_str, cflags);
    if (ret)
    {
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "3. %s\n", ebuff);
        goto end;
    }

    ret = regexec(&reg, test_str, 0, NULL, 0);
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "4. %s\n", ebuff);

end:
    regfree(&reg);

    return 0;
}

编译,运行结果如下:

[root@zxy 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_NOTBOLREG_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, reg_str, cflags);
    if (ret)
    {   
        regerror(ret, &reg, ebuff, 256);
        fprintf(stderr, "1. %s\n", ebuff);
        goto end;
    }   

    ret = regexec(&reg, test_str+1, 0, NULL, 0); 
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "2. %s\n", ebuff);

    ret = regexec(&reg, test_str+1, 0, NULL, REG_NOTBOL);
    regerror(ret, &reg, ebuff, 256);
    fprintf(stderr, "4. %s\n", ebuff);

end:
    regfree(&reg);

    return 0;
}

编译,运行结果如下:

[root@zxy regex]# ./test 
2. Success
4. No match

  结果说明:不加入REG_NOTBOL,一个字符串的不同位置是可以用’^’进行匹配,加入REG_NOTBOL,则不能进行匹配。

  第二个问题,我实在理解不了了,网上介绍的全是没有经过验证的。。。。。。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/159838.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • zabbix集成onealert验证报错:create media type failed! error message[通俗易懂]

    zabbix集成onealert验证报错:create media type failed! error message[通俗易懂]zabbix集成onealert验证报错:createmediatypefailed!errormessage一、报错详细信息[root@host-10-101-16-202bin]#bashinstall.sh1841b33f-1c97-1ae5-7dc2-e5a411b9eabfstarttocreateconfigfile…Zabbix管理地址:h…

  • C51浮点数显示、浮点数表示方法

    C51浮点数显示、浮点数表示方法C51中的浮点数存储方式–n年前曾在c51bbs论坛中发布过Float浮点形,它是符合IEEE-754标准的单精度浮点形数据,在十进制中具有7位有效数字。FLOAT型据占用四个字节(32位二进制数),在内存中的存放格式如下:字节地址(由低到高)0123浮点数内容MMMMMMMMMMMMMMMMEMMMMMMMSEEEEEEE其中,S为符号位,存放在最高字节

  • 有哪些你追了很多女生才明白的道理?

    有哪些你追了很多女生才明白的道理?

  • Linux读写执行(RWX)权限

    Linux读写执行(RWX)权限rwx权限对文件rwx权限 对文件的作用 读权限(r) 表示可读取此文件中的实际内容,例如,可以对文件执行cat、more、less、head、tail等文件查看命令。 写权限(w) 表示可以编辑、新增或者修改文件中的内容,例如,可以对文件执行vim、echo等修改文件数据的命令。注意,无权限不赋予用户删除文件的权利,除非用户对文件的上级目录拥有写权限才可以。 执行权限(x) 表示该文件具有被系统执行的权限。Window系统中查看一个文件是否为可执行文件,

  • C语言经典算法(七)——递归实现阶乘算法的两种方法「建议收藏」

    C语言经典算法(七)——递归实现阶乘算法的两种方法「建议收藏」今后继续整理算法并写出自己的理解和备注。C++实现的:递归实现阶乘算法N!1、递归实现n!题目描述:输入n值,求解n的阶乘方法一:累乘法方法二:递归法源码:一、递归实现n!1、累乘法#includeusingnamespacestd;#defineULunsignedlongULFactorial(ULn){int

  • 信道容量计算公式_信道均衡算法

    信道容量计算公式_信道均衡算法信道带宽=符号率*符号数*(188/204)注释:符号率&lt–&gt频宽(下行欧标频宽8MHz,上行有1.6MHz,3.2MHz,6.4MHz三种频宽);符号数&lt–&gt调制方式(符号数=Log2~调制方式,如QAM64的符号数为6,2的6次方=64)=====================================================…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号