Nov 25

使用Linux/Unix/BSD的regex库 不指定

felix021 @ 2012-11-25 00:01 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(6309) | Via 本站原创 | |
C/C++标准里头都没有正则表达式,C++还好,可以用上boost::regex,C的话,最简单的还是用系统自带的正则库了。

这个正则库真是相当简单,如果不关心内部琐碎的细节,实际上它只有2个类型、4个函数和7个常量,详细的后面会列出来(或者直接man regex),这里还是直接看例子比较实在:

代码1:email格式检测
#include <stdio.h>
#include <regex.h>
#include <assert.h>

int main() {
    //分配一个regex_t
    regex_t reg;
    //编译(使用POSIX扩展模式、并忽略大小写),确认编译成功(返回0)
    assert(regcomp(&reg, "^[a-z0-9_]+@([a-z0-9-]+\\.)+[a-z0-9]+$", REG_EXTENDED | REG_ICASE) == 0);
    int ret = regexec(&reg, "steve@rim.jobs", 0, NULL, 0); //执行搜索
    //看看返回值:0表示匹配成功,1表示REG_NOMATCH
    printf("ret = %d, nomatch = %d\n", ret, REG_NOMATCH);
    regfree(&reg); //记得释放空间
}


代码2:匹配xml的tag,取出key/value
int main() {
    const char *str = "<key>value</key>";
    regex_t reg;
    assert(regcomp(&reg, "<([^>]*)>([^<]*)</\\1>", REG_EXTENDED) == 0); //编译
    const int nr_match = 3;  //串本身 + 2个子匹配
    regmatch_t matches[nr_match]; //存储匹配的起始位置和结束位置
    int ret = regexec(&reg, str, nr_match, matches, 0);
    if (ret == 0) { //匹配成功
        for (int i = 0; i < nr_match; i++) { //先输出整个串,再依次输出子匹配
            for (int j = matches[i].rm_so; j < matches[i].rm_eo; j++) // [起始, 结束)
                putchar(str[j]);
            putchar('\n');
        }
    }
    else if (ret == REG_NOMATCH) { //匹配失败
        printf("no match\n");
    }
    else { //执行错误
        char msgbuf[256];
        regerror(ret, &reg, msgbuf, sizeof(msgbuf)); //输出错误信息至字符数组
        printf("error: %s\n", msgbuf);
    }
    regfree(&reg);
    return 0;
}

//运行结果:
<key>value</key>
key
value


代码3:找出所有匹配的字符串(regexec只匹配第一个)
int main() {
    regex_t reg;
    const char *str = "<k1>v1</k1><k2>v2</k2><k3>v3</k3>";
    assert(regcomp(&reg, "<([^>]*)>([^<]*)</\\1>", REG_EXTENDED) == 0);
    const int nr_match = 3;
    regmatch_t matches[nr_match];

    const char *start = str;
    while (1) {
        int ret = regexec(&reg, start, nr_match, matches, 0);
        if (ret == 0)
        { 
            for (int i = 0; i < nr_match; i++)
            { 
                for (int j = matches[i].rm_so; j < matches[i].rm_eo; j++)
                    putchar(start[j]);
                putchar('\n');
            } 
            start += matches[0].rm_eo;  //下次从 这次匹配末尾 开始搜索
            continue;
        } 
        if (ret == REG_NOMATCH)
            printf("no match\n");
        else {
            char msgbuf[256];
            regerror(ret, &reg, msgbuf, sizeof(msgbuf));
            printf("error: %s\n", msgbuf);
        } 
        break;
    }
    regfree(&reg);
    return 0;
}

//输出:
<k1>v1</k1>
k1
v1
<k2>v2</k2>
k2
v2
<k3>v3</k3>
k3
v3
no match



==== 分割线 ====

上面给出的几个例子能够满足regex的基本使用了,这里把前面提到的2、4、7给列出来,供参考。

//用于储存编译好的正则
typedef struct re_pattern_buffer  regex_t ;

//用于存储匹配到的位置(起始、结束偏移量,rm_so是RegexMatch_StartOffset的首字母简写)
typedef struct {
    regoff_t rm_so;
    regoff_t rm_eo;
} regmatch_t;

//将regex正则表达式 编译存储到preg指向的regex_t中去,该regex_t需要事先分配好。编译成功返回0。
int regcomp(regex_t *preg, const char *regex, int cflags);

//其中cflags可以是以下几项的异或
    REG_EXTENDED  //启用posix扩展模式,(){}+这些字符变成元字符
    REG_ICASE        //忽略大小写
    REG_NOSUB      //只匹配,不保存匹配到的正则位置
    REG_NEWLINE    //启用多行模式:. 不能匹配换行符,且 ^和$可以匹配\n之后的位置和\n之前的位置

//释放编译使额外分配的空间(不会释放regex_t本身)
void regfree(regex_t *preg);

//执行搜索匹配:查找string中满足preg的第一个串,将串的始末位置保存到pmatch[0].rm_so/rm_eo;
//子匹配依次保存到pmatch[1], pmatch[2], ... 调用者要保证匹配的数量不超过nmatch。
//匹配成功返回0,无匹配返回 <REG_NOMATCH> ,其他是出错(比如参数错误)。
int regexec(const regex_t *preg, const char *string,
                size_t nmatch, regmatch_t pmatch[], int eflags);

//其中eflags可以是以下的异或
REG_NOTBOL  //无视^规则(Beginning Of Line):将字符串分段匹配的时候,后面可能不希望匹配到^
REG_NOTEOL  //无视$规则




欢迎扫码关注:




转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]