使用C中的regex.h计算匹配数

时间:2016-05-02 04:30:33

标签: c regex

我在C中使用POSIX正则表达式regex.h来计算英语文本片段中短语的出现次数。 但regexec(...)的返回值仅表示是否找到匹配项。所以我尝试使用nmatchmatchptr来查找不同的外观,但是当我打印出来自matchptr的匹配项时,我刚收到第一个短语的第一个索引出现在我的文本中。

这是我的代码:

#include <sys/types.h>
#include <regex.h>
#include <stdio.h>

#define MAX_MATCHES 20 //The maximum number of matches allowed in a single string

void match(regex_t *pexp, char *sz) {
    regmatch_t matches[MAX_MATCHES];
    if (regexec(pexp, sz, MAX_MATCHES, matches, 0) == 0) {
    for(int i = 0; i < MAX_MATCHES; i++)
        printf("\"%s\" matches characters %d - %d\n", sz, matches[i].rm_so, matches[i].rm_eo);
    } 
    else {
        printf("\"%s\" does not match\n", sz);
    }
}

int main(int argc, char* argv[]) {
    int rv;
    regex_t exp;
    rv = regcomp(&exp, "(the)", REG_EXTENDED | REG_ICASE);
    if (rv != 0) {
        printf("regcomp failed\n");
    }
    match(&exp, "the cat is in the bathroom.");
    regfree(&exp);
    return 0;
}

如何让此代码报告字符串(the)中正则表达式the cat is in the bathroom的两个不同匹配?

1 个答案:

答案 0 :(得分:5)

您已正确理解pmatch的含义。它不用于获取重复的模式匹配。它用于获取一个匹配的位置及其可能的子组。正如regcomp(3)的Linux手册所说:

  

从第i个开始开始的子表达式的偏移量      括号存储在pmatch [i]中。整个正则表达式的匹配地址存储在          pmatch [0]。 (注意,要返回N个子表达式匹配的偏移量,nmatch必须至少为N + 1.)          任何未使用的结构元素都将包含值-1。

如果您有正则表达式this (\w+) costs (\d+) USD,则括号(\w+)(\d+)中有2个捕获组;现在,如果nmatch设置为至少3,则pmatch[0]将包含整个匹配的开始和结束索引,pmatch[1]组的(\w+)开始和结束以及{pmatch[2] 1}}用于(\d+)组。

以下代码应打印连续匹配的范围(如果有),如果模式从不匹配,则打印字符串"<the input string>" does not contain a match

它经过精心构造,因此它也适用于零长度正则表达式(空正则表达式,或者说正则表达式#?将匹配每个字符位置,包括在最后一个字符之后; 28个匹配将为输入the cat is in the bathroom.

报告正则表达式
#include <sys/types.h>
#include <regex.h>
#include <stdio.h>
#include <string.h>


void match(regex_t *pexp, char *sz) {
    // we just need the whole string match in this example    
    regmatch_t whole_match;

    // we store the eflags in a variable, so that we can make
    // ^ match the first time, but not for subsequent regexecs
    int eflags = 0;
    int match = 0;
    size_t offset = 0;
    size_t length = strlen(sz);

    while (regexec(pexp, sz + offset, 1, &whole_match, eflags) == 0) {
        // do not let ^ match again.
        eflags = REG_NOTBOL;
        match = 1;
        printf("range %zd - %zd matches\n",
               offset + whole_match.rm_so,
               offset + whole_match.rm_eo);

        // increase the starting offset
        offset += whole_match.rm_eo;

        // a match can be a zero-length match, we must not fail
        // to advance the pointer, or we'd have an infinite loop!
        if (whole_match.rm_so == whole_match.rm_eo) {
            offset += 1;
        }

        // break the loop if we've consumed all characters. Note
        // that we run once for terminating null, to let
        // a zero-length match occur at the end of the string.
        if (offset > length) {
            break;
        }
    }
    if (! match) {
        printf("\"%s\" does not contain a match\n", sz);
    }
}


int main(int argc, char* argv[]) {
    int rv;
    regex_t exp;
    rv = regcomp(&exp, "(the)", REG_EXTENDED | REG_ICASE);
    if (rv != 0) {
        printf("regcomp failed\n");
    }
    match(&exp, "the cat is in the bathroom.");
    regfree(&exp);
    return 0;
}

P.S。,在这种情况下,你的正则表达式(the)中的括号是不必要的;你可以写the(你最初在同一位置获得2场比赛的困惑是因为你得到(the)的一场比赛和the的一场比赛,如果你没有这些括号,你的代码只会打印一次匹配的位置。)