【问题标题】:Regex seems to be wrong - cannot find e-mail正则表达式似乎是错误的 - 找不到电子邮件
【发布时间】:2014-05-07 14:01:46
【问题描述】:

我在尝试查找电子邮件地址时遇到了问题。我不知道可能是什么问题:(

static int contains_mail(const unsigned char *buffer, int length, int detmode)
{
    const char *reg_exp = "([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z0-9._%+-]+)";

    regex_t regex;
    int reti;
    regmatch_t matches[2];

    int start0, end0, start1, end1;

    reti = regcomp(&regex, reg_exp, REG_EXTENDED);

    if(reti){ fprintf(stderr, "Could not compile regex\n"); exit(1); }

    reti = regexec(&regex, buffer, 2, matches, 0);

    start0 = matches[0].rm_so;
    end0 = matches[0].rm_eo;
    start1 = matches[1].rm_so;
    end1 = matches[1].rm_eo;

    printf("start0: %d", start0);
    printf("end0: %d", end0);
    printf("start1: %d", start1);
    printf("end1: %d", end1);

    if( !reti ){
        //printf("1");
        return 1;
    } else {
        //printf("0");
        return 0;
    }
}

示例输入文件:

dfo gpdf eriowepower riwope d@b.pl rwepoir weporsdfi dsfdfasdas@sdfaasdas.pl OSIDQOPWIEPOQWIE sdfs@asdsa.pl
WERO IWUEOIRU OWIERU WOIER asdas@asdasd.pl
aposidasop aposdi aspod iaspodi aspoid aspodi sdfsddfsd@asdasd.pl
werowerowe

看起来是这样开始的:

start0: 28end0: 28start1: 1end1: 8

但是看起来它不知道电子邮件的结尾是什么所以我无法计算它:(

【问题讨论】:

  • 您的 ad-hoc 正则表达式不允许 localpart 中有许多允许的字符。不过,至少允许+ 值得称赞。
  • 欢迎来到 SO。请阅读How to Askhelp center 了解如何提问。使用正确的类别进行标记不仅可以突出显示语法,正确的标记还可以使某人更有可能找到并回答您的问题。标记时请参考摘录,如果有疑问,甚至是完整的标记维基。为您重新标记。

标签: c regex posix email-address


【解决方案1】:

一个简单的问题,你是如何传入输入文件的?好像我定义然后像下面这样调用它:

char string[] = "dfo gpdf eriowepower riwope d@b.pl rwepoir weporsdfi dsfdfasdas@sdfaasdas.pl OSIDQOPWIEPOQWIE sdfs@asdsa.pl\n\
WERO IWUEOIRU OWIERU WOIER asdas@asdasd.pl\n\
aposidasop aposdi aspod iaspodi aspoid aspodi sdfsddfsd@asdasd.pl\n\
werowerowe\n";

contains_mail(string, 0, 0);

并修改您的contains_mail 函数以重复调用regexec,如下所示:

reti = regexec(&regex, buffer, 2, matches, 0);
while (reti == 0) {
        start0 = matches[0].rm_so;
        end0 = matches[0].rm_eo;
        start1 = matches[1].rm_so;
        end1 = matches[1].rm_eo;

        printf("start0: %d ", start0);
        printf("end0: %d\n", end0);
        printf("start1: %d ", start1);
        printf("end1: %d\n", end1);
        printf("email: %.*s\n", end1 - start1, buffer + start1);
        buffer += end1;
        reti = regexec(&regex, buffer, 2, matches, REG_NOTBOL);
} 

我得到所有匹配项:

$ ./email_regex
start0: 28 end0: 34
start1: 28 end1: 34
email: d@b.pl
start0: 19 end0: 42
start1: 19 end1: 42
email: dsfdfasdas@sdfaasdas.pl
start0: 18 end0: 31
start1: 18 end1: 31
email: sdfs@asdsa.pl
start0: 28 end0: 43
start1: 28 end1: 43
email: asdas@asdasd.pl
start0: 47 end0: 66
start1: 47 end1: 66
email: sdfsddfsd@asdasd.pl

我同意其他 cmets 的观点,您的正则表达式可能不是获取电子邮件地址的最佳选择。但你到底想做什么?

【讨论】:

    【解决方案2】:

    函数regexec 总是最多只能找到一次你的正则表达式。第一个匹配项(索引为 0)包含整个匹配项的开始结束位置,以下匹配项包含括号中子表达式的数据。 (您示例中整个表达式周围的括号没有任何作用,但它们导致匹配 0 和 1 的相同位置,可能会误导您认为相同的表达式被一遍又一遍地解析。)

    您可以在 while 循环中查找您的表达式,在此循环中您在成功匹配后推进指针以查找更多电子钉地址。您的代码的以下修改会打印找到的所有电子邮件地址并返回匹配的数量。

    static int contains_mail(const char *buffer, int length)
    {
        const char *reg_exp =
            "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z0-9._%+-]+";
    
        regex_t regex;
        regmatch_t match;
        int count = 0;
    
        if (regcomp(&regex, reg_exp, REG_EXTENDED) < 0) {
            fprintf(stderr, "Could not compile regex\n");
            exit(1);
        }
    
        while (regexec(&regex, buffer, 1, &match, 0) == 0) {
            int start = match.rm_so;
            int end = match.rm_eo;
    
            printf("%.*s\n", end - start, buffer + start);
            count++;
            buffer = buffer + end;
        }
    
        return count;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 2015-08-07
      • 2011-06-05
      • 2012-07-20
      • 2011-12-28
      • 2012-01-02
      • 2015-12-03
      相关资源
      最近更新 更多