You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用正则对比含变量的预定义文本与目标文本,返回布尔值或匹配率

含变量模板与目标文本的正则匹配实现方案

核心思路

要对比带{var}变量的预定义模板和目标文本,核心是将模板转换为正则表达式,通过正则匹配判断结构是否吻合,再计算匹配相似度:

  1. 模板转正则:将{var}替换为正则捕获组(通用场景用(.*?),特定格式可替换为\d+、[A-Z]+等),同时转义正则特殊字符。
  2. 正则匹配:用Kannel库的gw_regex_comp_real编译正则,执行匹配得到布尔结果。
  3. 匹配百分比计算:完全匹配返回100%;匹配失败时,统计模板固定文本在目标中的匹配占比,或用编辑距离计算相似度。

模板转正则规则

针对你的示例模板:

Hi {var}, Your last call was from {var} at {var} {var} was {var}.
Thank you for using Cloud PBX Services.

转换后的正则(启用扩展正则+换行模式):

^Hi (.*?), Your last call was from (.*?) at (.*?) (.*?) was (.*?)\.\nThank you for using Cloud PBX Services\.
  • ^和$锚定确保完全匹配文本整体结构
  • (.*?)采用非贪婪匹配,避免变量内容覆盖后续固定文本
  • 转义.、\n等正则特殊字符

基于Kannel库的具体实现

编译正则的Kannel函数(中文注释版)

// Kannel库的正则编译核心函数
// 参数说明:
//   pattern: 待编译的正则表达式(Octstr类型)
//   cflags: 编译标志(如REG_EXTENDED启用扩展正则,REG_NEWLINE支持换行匹配)
//   file/line/func: 调用位置信息(用于错误日志定位)
// 返回:编译后的regex_t指针,失败返回NULL
regex_t *gw_regex_comp_real(const Octstr *pattern, int cflags, const char *file,
                            long line, const char *func)
{
    int rc;
    regex_t *preg;

    preg = gw_malloc(sizeof(regex_t)); // 分配正则结构体内存

    // 执行正则编译
    if ((rc = regcomp(preg, pattern ? octstr_get_cstr(pattern) : NULL, cflags)) != 0) {
        char buffer[512];
        regerror(rc, preg, buffer, sizeof(buffer)); // 获取编译错误信息
        // 打印错误日志,包含调用上下文
        error(0, "%s:%ld: %s: 正则表达式`%s`编译失败: %s (调用位置: %s:%ld:%s.)",
              __FILE__, (long) __LINE__, __func__, octstr_get_cstr(pattern), buffer,
              (file), (long) (line), (func));
        gw_free(preg); // 释放已分配内存
        return NULL;
    }

    return preg;
}

完整匹配逻辑代码

#include <string.h>
#include "kannel/octstr.h"
#include "kannel/regex.h"

// 将模板转换为正则表达式
Octstr *template_to_regex(const Octstr *template) {
    if (!template) return NULL;

    Octstr *regex = octstr_duplicate(template);
    // 先转义正则特殊字符
    const char *special_chars[] = {".", "^", "$", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\", NULL};
    for (int i = 0; special_chars[i]; i++) {
        Octstr *from = octstr_create(special_chars[i]);
        Octstr *to = octstr_create("\\");
        octstr_append(to, from);
        regex = octstr_replace(regex, from, to);
        octstr_destroy(from);
        octstr_destroy(to);
    }
    // 将{var}替换为非贪婪捕获组
    regex = octstr_replace(regex, octstr_create("{var}"), octstr_create("(.*?)"));
    // 添加行首行尾锚定
    octstr_prepend(regex, octstr_create("^"));
    octstr_append(regex, octstr_create("$"));
    return regex;
}

// 对比模板与目标文本,返回匹配结果(1=成功,0=失败),可选返回匹配百分比
int match_template(const Octstr *template, const Octstr *target, float *match_percent) {
    if (!template || !target) {
        if (match_percent) *match_percent = 0.0f;
        return 0;
    }

    Octstr *regex_str = template_to_regex(template);
    if (!regex_str) {
        if (match_percent) *match_percent = 0.0f;
        return 0;
    }

    // 编译正则:启用扩展正则+换行模式
    regex_t *preg = gw_regex_comp_real(regex_str, REG_EXTENDED | REG_NEWLINE, __FILE__, __LINE__, __func__);
    octstr_destroy(regex_str);

    if (!preg) {
        if (match_percent) *match_percent = 0.0f;
        return 0;
    }

    // 执行匹配
    int rc = regexec(preg, octstr_get_cstr(target), 0, NULL, 0);
    regfree(preg); // 释放正则结构体

    if (rc == 0) {
        // 完全匹配成功
        if (match_percent) *match_percent = 100.0f;
        return 1;
    } else {
        // 计算匹配百分比:统计模板固定文本在目标中的匹配占比
        if (match_percent) {
            Octstr *fixed_part = octstr_duplicate(template);
            fixed_part = octstr_replace(fixed_part, octstr_create("{var}"), octstr_create(""));
            int fixed_len = octstr_len(fixed_part);
            if (fixed_len == 0) {
                *match_percent = 0.0f;
            } else {
                const char *fixed_cstr = octstr_get_cstr(fixed_part);
                const char *target_cstr = octstr_get_cstr(target);
                int matched_chars = 0;
                const char *pos = target_cstr;
                // 统计固定文本在目标中的出现总长度
                while ((pos = strstr(pos, fixed_cstr)) != NULL) {
                    matched_chars += octstr_len(fixed_part);
                    pos += octstr_len(fixed_part);
                }
                *match_percent = (float)matched_chars / fixed_len * 100.0f;
                // 避免百分比超过100%
                if (*match_percent > 100.0f) *match_percent = 100.0f;
            }
            octstr_destroy(fixed_part);
        }
        return 0;
    }
}

示例验证

  • 成功示例1/2:目标文本符合模板结构,返回1,匹配百分比100%
  • 失败示例:目标文本结构不符,返回0,匹配百分比约为47%(具体数值由代码计算)

内容的提问来源于stack exchange,提问作者Vinayak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 01:01:19