在 C++ 后端、工业视觉、离线数据处理场景中,经常需要处理错别字、乱序文本、录入误差等模糊匹配需求。原生手写编辑距离效率极低,传统 fuzzywuzzy 存在协议限制。本文介绍纯头文件、MIT 协议高性能模糊匹配库 rapidfuzz-cpp,覆盖业务适用场景、三大 CMake 集成方案、主流相似度算法横向对比、完整可运行示例代码,跨 Windows/Linux/macOS 平台。

一、rapidfuzz-cpp 库简介

1.1 项目地址

GitHub:https://github.com/rapidfuzz/rapidfuzz-cpp rapidfuzz-cpp 是 Python 爆款模糊匹配库 RapidFuzz 的原生 C++ 移植实现,纯头文件库,无第三方依赖,仅依赖 C++17 标准库。

1.2 核心优势

  1. 性能碾压传统实现 底层采用 SIMD 向量化、带状 DP、阈值提前剪枝优化,相比手写 Levenshtein、旧版 fuzzywuzzy 速度提升数十倍,支持百万级文本批量匹配;
  2. 商用无限制 MIT 开源协议,无 GPL 传染约束,嵌入式、ToB/ToC 后端均可免费商用;
  3. 算法体系完整 提供距离计算、归一化相似度打分、批量 TopN 检索三层接口,覆盖绝大多数文本模糊场景;
  4. 跨平台兼容 GCC8+/Clang10+/MSVC2019+ 全平台支持,ARM 嵌入式设备也可正常编译;
  5. 接入成本极低 头文件库无需编译静态库,CMake 一行链接即可使用,提供三种集成方案适配不同项目架构。

二、rapidfuzz-cpp 典型业务适用场景

  • 检索纠错 电商商品搜索、知识库查询,用户输入错字、简写、缺字自动匹配标准名称(如 “苹国 15” 匹配 “苹果 15”);
  • 数据清洗与去重 客户姓名、地址、设备台账存在人工录入误差,批量合并相似重复数据,替代低效 SQL LIKE
  • OCR 视觉文本校正 机器视觉识别文字存在噪点、残缺字符,通过模糊匹配修正识别结果;
  • 命令 / 文件名智能提示 运维工具、客户端输入不完整关键词,自动推荐相似度最高候选列表;
  • 工业型号模糊匹配 设备型号简写、录入错误,快速关联标准设备库;
  • 短文本查重、评论内容过滤

三、主流相似度算法横向对比

库分为三大核心模块:

  1. rapidfuzz::distance:底层距离算法,输出编辑次数 / 归一化距离;
  2. rapidfuzz::fuzz:归一化相似度(0~100),业务最常用;
  3. rapidfuzz::process:批量检索,一键提取候选集中 TopN 相似文本。
接口 计算逻辑 适用场景 输出范围
fuzz::ratio 全局完整字符串整体相似度 两段完整标准文本对比 0~100,越高越相似
fuzz::partial_ratio 局部子串匹配,长文本包含短文本自动高分 关键词检索、长文档匹配短句 0~100
fuzz::token_sort_ratio 分词后打乱词语顺序再匹配,忽略语序 商品名、地址、短语乱序匹配 0~100
distance::levenshtein_distance 标准编辑距离(增 / 删 / 替换字符) 精确统计最少修改字符数 非负整数,数值越大差异越大
distance::osa_distance 允许相邻字符交换的编辑距离 手输颠倒错别字(如 “ab” 写成 “ba”) 非负整数
distance::jaro_winkler_normalized 加权前缀匹配,短文本相似度放大 人名、短型号、短关键词纠错 0~1

算法选型建议

  • 商品 / 地址乱序匹配:token_sort_ratio
  • 长文本检索短句:partial_ratio
  • 人名、短关键词纠错:jaro_winkler
  • 需要精确统计修改字符数量:levenshtein_distance
  • 通用完整文本打分:ratio

四、三种 CMake 集成方案(覆盖全部项目场景)

环境前置要求

  • C++17 及以上编译器
  • CMake 3.14 及以上

方案 1:FetchContent 自动拉取(新项目首选,推荐)

编译时自动从 GitHub 下载源码,无需手动下载、无需 git 子模块,开箱即用。

根目录完整 CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(RapidFuzzDemo LANGUAGES CXX)

# 开启C++17标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 自动拉取rapidfuzz-cpp源码
include(FetchContent)
FetchContent_Declare(
    rapidfuzz
    GIT_REPOSITORY https://github.com/rapidfuzz/rapidfuzz-cpp.git
    GIT_TAG main
)
FetchContent_MakeAvailable(rapidfuzz)

# 编译测试程序
add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE rapidfuzz::rapidfuzz)

方案 2:Git Submodule 子模块(存量项目 / 离线编译)

适合项目统一管理第三方库,断网环境可正常编译:

  1. 命令行添加子模块
    git submodule add https://github.com/rapidfuzz/rapidfuzz-cpp 3rdparty/rapidfuzz-cpp
    git submodule update --init
cmake_minimum_required(VERSION 3.14)
project(RapidFuzzDemo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)

# 引入本地子模块库
add_subdirectory(3rdparty/rapidfuzz-cpp)

add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE rapidfuzz::rapidfuzz)

方案 3:系统全局安装(服务器多项目共享)

将库安装至系统目录,所有项目可通过 find_package 直接调用:

1.编译安装命令

git clone https://github.com/rapidfuzz/rapidfuzz-cpp.git
cd rapidfuzz-cpp
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
sudo cmake --install .

2.项目 CMake 配置

cmake_minimum_required(VERSION 3.14)
project(RapidFuzzDemo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)

# 查找系统已安装的rapidfuzz
find_package(rapidfuzz REQUIRED)

add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE rapidfuzz::rapidfuzz)

五、完整可运行 C++ 代码示例

覆盖预处理、各类相似度打分、底层编辑距离、批量 TopN 检索,复制即可编译运行。 新建 main.cpp

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cctype>

// 相似度打分接口
#include <rapidfuzz/fuzz.hpp>
// 底层距离算法
#include <rapidfuzz/distance/Levenshtein.hpp>
#include <rapidfuzz/distance/JaroWinkler.hpp>
// 批量检索工具
#include <rapidfuzz/process.hpp>

using namespace rapidfuzz;

// 文本预处理:统一小写,消除大小写干扰
std::string preprocess(std::string text)
{
    std::transform(text.begin(), text.end(), text.begin(),
        [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
    return text;
}

int main()
{
    // 标准文本、错误输入文本
    std::string standardText = "iPhone 15 Pro Max";
    std::string typoText = "iphone 15 pro max";
    std::string shuffleText = "pro max iphone 15";
    std::string irrelevantText = "Xiaomi 14 Ultra";

    // 统一预处理
    std::string sStandard = preprocess(standardText);
    std::string sTypo = preprocess(typoText);
    std::string sShuffle = preprocess(shuffleText);

    // 1. 全局整体相似度 ratio
    std::cout << "=====1. 全局相似度 ratio=====\n";
    double ratioScore = fuzz::ratio(sStandard, sTypo);
    std::cout << standardText << " vs " << typoText << " 相似度:" << ratioScore << "\n\n";

    // 2. 局部匹配 partial_ratio(长文本包含短关键词)
    std::cout << "=====2. 局部匹配 partial_ratio=====\n";
    double partialScore = fuzz::partial_ratio(
        preprocess("iPhone手机"),
        preprocess("2025新款iPhone 15 Pro Max手机壳")
    );
    std::cout << "局部匹配分值:" << partialScore << "\n\n";

    // 3. 乱序分词匹配 token_sort_ratio
    std::cout << "=====3. 词语乱序匹配 token_sort_ratio=====\n";
    double tokenScore = fuzz::token_sort_ratio(sStandard, sShuffle);
    std::cout << standardText << " vs " << shuffleText << " 相似度:" << tokenScore << "\n\n";

    // 4. Levenshtein编辑距离(最少修改字符数)
    std::cout << "=====4. Levenshtein编辑距离=====\n";
    size_t editCount = distance::levenshtein_distance(sStandard, sTypo);
    std::cout << "最少修改字符数量:" << editCount << "\n\n";

    // 5. Jaro-Winkler 短文本相似度
    std::cout << "=====5. Jaro-Winkler 短文本匹配=====\n";
    double jwScore = distance::jaro_winkler_normalized(sStandard, sTypo) * 100;
    std::cout << "Jaro-Winkler相似度:" << jwScore << "\n\n";

    // 6. 批量候选集检索 Top3 相似文本
    std::cout << "=====6. 批量检索Top3相似商品=====\n";
    std::vector<std::string> candidateList = {
        "Xiaomi 14 Ultra",
        "iPhone 14",
        "iPhone 15 Pro Max",
        "iPhone 15 mini",
        "iphone 15 pro max",
        "HUAWEI Mate60"
    };
    // 参数:查询文本、候选列表、匹配函数、最低相似度阈值、返回条数
    auto matchResults = process::extract(
        standardText,
        candidateList,
        fuzz::ratio,
        60.0,
        3
    );
    for (const auto& item : matchResults)
    {
        std::cout << "相似度:" << item.first << " | 文本:" << item.second << "\n";
    }

    return 0;
}

编译运行(Linux/macOS)

mkdir build && cd build
cmake ..
make -j$(nproc)
./demo

Windows:使用 CMake 生成 VS 解决方案,选择 Release 模式编译运行。

输出示例

=====1. 全局相似度 ratio=====
iPhone 15 Pro Max vs iphone 15 pro max 相似度:100

=====2. 局部匹配 partial_ratio=====
局部匹配分值:100

=====3. 词语乱序匹配 token_sort_ratio=====
iPhone 15 Pro Max vs pro max iphone 15 相似度:100

=====4. Levenshtein编辑距离=====
最少修改字符数量:0

=====5. Jaro-Winkler 短文本匹配=====
Jaro-Winkler相似度:100

=====6. 批量检索Top3相似商品=====
相似度:100 | 文本:iPhone 15 Pro Max
相似度:100 | 文本:iphone 15 pro max
相似度:76.4706 | 文本:iPhone 15 mini

六、生产环境优化方案

  1. 统一文本预处理 提前去除标点、多余空格、统一大小写,减少无效字符干扰,提升匹配准确率;
  2. 利用 cutoff 阈值提前剪枝 底层 distance 接口支持传入最大允许距离,差异过大时直接终止计算,海量数据性能大幅提升:
    // 超过3次修改直接停止计算
    size_t dist = distance::levenshtein_distance(a, b, 3);
  3. Release 模式编译 关闭 Debug 断言,编译器开启 O2/O3 优化,充分发挥 SIMD 加速特性;
  4. 多线程批量处理 结合线程池拆分候选列表并行调用process::extract,支撑百万级文本实时匹配;
  5. 合理设置相似度阈值 业务检索建议阈值 70~80,低于阈值直接过滤,减少无效结果。

七、常见问题与踩坑

  1. 编译报错 C++ 版本不匹配 CMake 必须指定CMAKE_CXX_STANDARD 17,MSVC 添加编译参数 /std:c++17
  2. 中文匹配分数异常 源码文件统一使用 UTF-8 编码,Windows 编译追加 /utf-8 编译选项;
  3. FetchContent 拉取仓库失败 网络问题切换 Submodule 方案,手动下载源码放入 3rdparty 目录;
  4. 匹配速度慢 检查是否处于 Debug 模式,未使用 cutoff 阈值做提前过滤。

八、总结

rapidfuzz-cpp 填补了 C++ 生态高性能模糊字符串匹配的空白,纯头文件无依赖、MIT 商用授权、算法覆盖全业务场景。三种 CMake 集成方案适配全新项目、存量工程、服务器全局部署,内置批量 TopN 检索接口可直接落地搜索纠错、数据清洗、OCR 校正等业务,是工业级 C++ 模糊匹配场景的首选库。

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐