c - 在 C 中使用正则表达式组
问题描述
我需要在 C 中获取与我的正则表达式匹配的组来操作 Java 程序日志。
我已经测试了正则表达式:
(Client:\s[a-zA-Z\s]+)|(Wallet:\s[a-zA-Z0-9]+)|(ID\s*:\s*[0-9]{3}.{0,1}[0-9]{3}.{0,1}[0-9]{3}-{0,1}[0-9]{2})
在这里,它的工作原理。
但是在我的 C 程序中,它并不能很好地工作。
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
const char *source =
"[com.example.app.JavaClass.JavaMethod(JavaClass.java:1)] (Thread-1) - "
"Client: FirstName MiddleName AnotherName LastName, Wallet: WL01, "
"Agency: 9999, ID: 06611486123, Ticket: TKR211";
const char *regexString =
"(Client:\\s[a-zA-Z[:space:]]+)|(Wallet:\\s[a-zA-Z0-9]+)|(ID\\s*:\\s*[0-"
"9]{3}.{0,1}[0-9]{3}.{0,1}[0-9]{3}-{0,1}[0-9]{2})";
regex_t regexCompiled;
regcomp(®exCompiled, regexString, REG_ICASE | REG_EXTENDED);
size_t ngroups = regexCompiled.re_nsub + 1;
regmatch_t *groups = malloc(ngroups * sizeof(regmatch_t));
regexec(®exCompiled, source, ngroups, groups, 0);
char cursorCopy[strlen(source) + 1];
strcpy(cursorCopy, source);
size_t nmatched;
for (nmatched = 0; nmatched < ngroups; nmatched++) {
if (groups[nmatched].rm_so == (size_t)(-1)) {
break;
}
char *match =
calloc(groups[nmatched].rm_eo - groups[nmatched].rm_so, sizeof(char));
memcpy(match, &source[groups[nmatched].rm_so],
groups[nmatched].rm_eo - groups[nmatched].rm_so);
printf("Match: [%2u-%2u]: \"%s\"\n", groups[nmatched].rm_so,
groups[nmatched].rm_eo, match);
}
regfree(®exCompiled);
return 0;
}
执行:
$ gcc -Wall -Wextra -Wwrite-strings reg.c && ./a.out
生成输出:
Match: [70-119]: "Client: FirstName MiddleName AnotherName LastName"
Match: [70-119]: "Client: FirstName MiddleName AnotherName LastName"
但我想要的是:
Match: [xx-xx]: "Client: FirstName MiddleName AnotherName LastName"
Match: [xx-xx]: "Wallet: WL01"
Match: [xx-xx]: "ID: 06611486123"
有人可以告诉我是否可以使用 C 或我需要另一种方法?
编辑:
在我的情况下,某些字段(“客户”、“钱包”或“ID”)可能不会出现在日志中。
解决方案
您的正则表达式的组成如下:(a)|(b)|(c)
where a
, b
, andc
对应于Client
正则表达式、Wallet
正则表达式和ID
正则表达式。
这不是你想要的——你可以在你自己的RegExr中看到你得到的不是一场比赛,而是三场不同的比赛。在 C 中,您只匹配一次。
你真正想要完成的是只匹配你的source
字符串一次,并且让每个组都包含他们的字符串。换句话说,我们想改变你的正则表达式:
(a)|(b)|(c)
-> (a),(b),(c)
- 一个匹配整个字符串的单个匹配项。
这可以解决问题:
const char *regexString =
"(Client:\\s[a-zA-Z[:space:]]+), (Wallet:\\s[a-zA-Z0-9]+).*(ID\\s*:\\s*[0-"
"9]{3}.{0,1}[0-9]{3}.{0,1}[0-9]{3}-{0,1}[0-9]{2})";
我将第|
一个更改,
为分隔子字符串Client
和Wallet
子字符串的 a,我将第二个更改为封装了子字符串和子字符串之间的所有内容的|
a 。.*
Wallet
ID
现在运行它会给出:
Match: [70-164]: "Client: FirstName MiddleName AnotherName LastName, Wallet: WL01, Agency: 9999, ID: 06611486123"
Match: [70-119]: "Client: FirstName MiddleName AnotherName LastName"
Match: [121-133]: "Wallet: WL01"
Match: [149-164]: "ID: 06611486123"
第一行给出了整个匹配,而下面的行给出了每个单独组的内容。
一种更直观的看待方式来自:
至:
推荐阅读
- jenkins - 如何在 Jenkins 中使用来自 Github 包注册表的 npm 包?
- gradle - 如何禁用 gradle 的本地构建缓存,但保持启用远程缓存?
- loops - 在 for 循环中打印会改变列表类型?
- mysql - 时代的CONVERT_TZ?
- sql - 新添加的列未出现在同义词中
- javascript - Firefox 警告 .. 我可以禁止它,让它不显示吗?
- reactjs - 如何解决 index.js 文件中 Hook 的错误?
- python - 在包之间共享本地 python 脚本
- c++ - LED灯类型选择条件的语义错误
- r - 在 Power BI 列上运行 R 脚本