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

如何修复NMEA语句解析正则表达式以通过全部测试用例?

修复NMEA语句匹配的正则表达式

原正则的问题

原正则\$G([A-Z]{4}),(.*?)(\*[0-9A-Fa-f]{2})的核心缺陷:

  • 中间的.*?非贪婪匹配允许字段中出现*,会错误匹配带多个*的无效语句(比如$GPXXX,2*3,1*77)
  • 未限制语句的开头和结尾,可能匹配包含有效片段的长字符串
  • 未约束校验和必须是恰好2位十六进制字符,会错误匹配$GPXXX,*012这类校验和长度违规的语句

修复后的正则

^\$G[A-Z]{4},(?:[^*,]*,)*[^*,]*\*[0-9A-Fa-f]{2}$

正则规则拆解

  • ^:强制从字符串开头匹配,避免匹配片段
  • \$G[A-Z]{4}:匹配NMEA语句的标准前缀(以$G开头的5位大写字母,比如$GPGGA)
  • ,:前缀后的必填分隔逗号
  • (?:[^*,]*,)*:非捕获组,匹配0或多个合法字段(字段内容不能包含*和逗号,末尾带逗号)
  • [^*,]*:匹配最后一个字段(同样不能包含*和逗号,末尾不带逗号)
  • \*[0-9A-Fa-f]{2}:匹配唯一的校验和标记*,后跟恰好2位十六进制字符(大小写兼容)
  • $:强制匹配到字符串结尾,避免多余后缀

测试场景验证

有效语句(应匹配)

  • $GPGGA,123456.000,4812.3456,N,00923.4567,E,1,08,1.0,0.0,M,0.0,M,,*57
  • $GPRMC,123519,A,4807.038,N,00114.323,W,022.4,084.4,171100,,,A*45
  • $GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48

无效语句(应不匹配)

  • $GPXXX,2*3,1*77:中间字段包含*,违反格式规则
  • $GPXXX,*012:校验和为3位,不符合2位要求
  • $GPXXX,abc*def,ghi*01:存在多个*标记
  • $GPGGA,123456*01:缺少字段分隔逗号,格式错误

适配BOOST测试的代码示例

#include <boost/regex.hpp>
#include <iostream>
#include <vector>

int main() {
    const boost::regex nmea_regex(R"(^\$G[A-Z]{4},(?:[^*,]*,)*[^*,]*\*[0-9A-Fa-f]{2}$)");

    // 有效测试用例
    std::vector<std::string> valid_cases = {
        "$GPGGA,123456.000,4812.3456,N,00923.4567,E,1,08,1.0,0.0,M,0.0,M,,*57",
        "$GPRMC,123519,A,4807.038,N,00114.323,W,022.4,084.4,171100,,,A*45",
        "$GPVTG,054.7,T,034.4,M,005.5,N,010.2,K*48",
        "$GPGLL,4916.45,N,12311.12,W,225444,A,*1D"
    };

    // 无效测试用例
    std::vector<std::string> invalid_cases = {
        "$GPXXX,$77*01",
        "$GPXXX,2*3,1*77",
        "$GPXXX,*012",
        "$GPXXX,abc*def,ghi*01",
        "$GPGGA,123456*01",
        "$GPGGA,123456,*01"
    };

    std::cout << "Valid cases test:\n";
    for (const auto& s : valid_cases) {
        std::cout << "\"" << s << "\" => " << (boost::regex_match(s, nmea_regex) ? "MATCHED" : "UNMATCHED") << "\n";
    }

    std::cout << "\nInvalid cases test:\n";
    for (const auto& s : invalid_cases) {
        std::cout << "\"" << s << "\" => " << (boost::regex_match(s, nmea_regex) ? "MATCHED" : "UNMATCHED") << "\n";
    }

    return 0;
}

可选调整

如果需要支持语句末尾的\r\n换行符,可将正则修改为:

^\$G[A-Z]{4},(?:[^*,]*,)*[^*,]*\*[0-9A-Fa-f]{2}(?:\r\n)?$

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:53:19