如何修复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
相关产品推荐
相关产品推荐

