所以我目前的作业是用 C 实现一个类似 DBMS 的系统,我决定使用 linux POSIX 正则表达式匹配库。我正在编写玩具代码来学习东西,这是我对 DBMS 的“命令解析”部分的测试。帖子有点长,请多多包涵。
因此,基于此示例的完整程序代码:
char *toSubstring(const char *str, int start, int end)
{
char *buffer = malloc((end - start + 1) * sizeof *buffer);
memcpy(buffer, str + start, end - start);
*(buffer + (end - start)) = '\0';
return buffer;
}
int compile_regex(regex_t *r, const char *r_pattern)
{
int status = regcomp(r, r_pattern, REG_EXTENDED|REG_NEWLINE);
if (status != 0) {
char err_msg[MAX_ERR_MSG];
regerror(status, r, err_msg, MAX_ERR_MSG);
printf("REGEX error compiling '%s': %s\n", r_pattern, err_msg);
return status;
}
return 0;
}
int match_regex(regex_t *r, const char *r_text, char ***m_array, int n_matches)
{
int i, nomatch;
regmatch_t m_osets[n_matches];
*m_array = malloc(n_matches * sizeof **m_array);
nomatch = regexec(r, r_text, n_matches, m_osets, 0);
if (nomatch) {
printf("No matches\n");
return nomatch;
}
for (i = 0; i < n_matches ; i++) {
int start = (int) m_osets[i].rm_so;
int stop = (int) m_osets[i].rm_eo;
if (start==-1 || stop==-1) {
*(*(m_array)+i) = NULL;
printf("WARNING: Match block %d is void!\n", i);
} else {
*(*(m_array)+i) = toSubstring(r_text, start, stop);
printf("Match block %d @bytes %d:%d\n", i, start, stop);
}
}
return 0;
}
void chafree(char **c, int n)
{
int i;
for (i = 0; i < n; i++) {
if (*(c+i)!=NULL)
free(*(c+i));
}
free(c);
}
int main(int argc, char **argv)
{
int i, m;
regex_t r;
const char * r_text = *(argv+1);
const char * r_pattern = *(argv+2);
char **matches = NULL;
if (argc != 4) {
printf("Usage: ./program_name \"r_text\" \"r_pattern\" n_matches\n");
exit(1);
}
printf("Sweeping '%s' for '%s'\n", r_text, r_pattern);
compile_regex(&r, r_pattern);
match_regex(&r, r_text, &matches, atoi(*(argv+3)));
if (matches != NULL) {
for(i=0;i<atoi(*(argv+3));i++){
if(*(matches+i)!=NULL)
printf("$%d --> %s\n", i, *(matches+i));
else printf("$%d --> %p\n", i, *(matches+i));
}
chafree(matches, atoi(*(argv+3)));
}
regfree(&r);
return 0;
与我提供的示例略有不同的是,我将匹配项和捕获组存储在字符串向量中。
现在,当我运行程序时:
./regex_drills "insert whatever bananana" "([[:alpha:]]+)[[:blank:]]*([^\0]*)" 3
我收到的输出是:
Sweeping 'insert whatever bananana' for '([[:alpha:]]+)[[:blank:]]*([^\0]*)'
Match block 0 @bytes 0:23
Match block 1 @bytes 0:5
Match block 2 @bytes 7:23
$& --> insert whatever bananana!
$1 --> insert
$2 --> whatever bananana
根据正则表达式 101 ,正则表达式模式似乎没问题,但请注意完整表达式末尾的杂散“ ! ”。尽管正确解析了捕获组,但异常字符(到目前为止)发生在整个表达式范围内,并且对于迄今为止使用的测试用例,仅当它恰好是 24 字节长时。这可能是一个非常愚蠢的错误,我很抱歉。
此外,任何关于如何在 C 中以更好、也许更优雅的方式处理正则表达式的建议都将非常受欢迎。非常感谢提前。
编辑
因此,根据回复,这是内部的偏移误差toSubstring
。它现在已修复,并且输出很流畅,因为它们应该如此。正如评论中所建议的,我还稍微清理了代码。
与之前发生的情况不同,使用 valgrind 进行的有点侵入性的运行不会显示任何错误或未定义的行为:
$ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./regex_drills "insert whatever bananana" "([[:alpha:]]+)[[:blank:]]*([^\0]*)" 3
==7051== Memcheck, a memory error detector
==7051== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7051== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==7051== Command: ./regex_drills insert\ whatever\ bananana ([[:alpha:]]+)[[:blank:]]*([^\\0]*) 3
==7051==
Sweeping 'insert whatever bananana' for '([[:alpha:]]+)[[:blank:]]*([^\0]*)'
Match block 0 @bytes 0:24
Match block 1 @bytes 0:6
Match block 2 @bytes 7:24
$0 --> insert whatever bananana
$1 --> insert
$2 --> whatever bananana
==7051==
==7051== HEAP SUMMARY:
==7051== in use at exit: 0 bytes in 0 blocks
==7051== total heap usage: 167 allocs, 167 frees, 18,458 bytes allocated
==7051==
==7051== All heap blocks were freed -- no leaks are possible
==7051==
==7051== For counts of detected and suppressed errors, rerun with: -v
==7051== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
我要感谢大家的快速反应。我从中学到了很多。