无法找到为什么我的正则表达式匹配在读取 GPS 缓冲区时有点被破坏

问题描述 投票:0回答:1

我正在使用 C++ 11 阅读 NMEA-0183 消息。

代码修改后,我看到某种缓冲区崩溃,但我不明白为什么。欢迎帮助。

这是我得到的日志:

GPS: probably data
GPS: $GPGLL,4851.87109,N,00226.20521,E,092741.00,A,A*6D
GPS: match is: 1 | 5 matches
GPS: match #0: 17a30a0 | buffer: 5f452ee0
GPS: match #0: B2z
GPS: match #1: 5f452ed0 | buffer: 5f452ee0
GPS: match #1: 
GPS: match #2: 5f452ed0 | buffer: 5f452ee0
GPS: match #2: N
GPS: match #3: 5f452ed0 | buffer: 5f452ee0
GPS: match #3: 00226.20521
GPS: match #4: 5f452ed0 | buffer: 5f452ee0
GPS: match #4: E
GPS: match is: latitude:0.000000 | longitude: 2.436754
GPS: end of processing

我期望这样的事情(注意这是 GPGLL 消息,其工作方式与上面的消息相同):

GPS: probably data
GPS: $GPRMC,164548.00,A,4851.85459,N,00226.22224,E,0.721,,060923,,,A*7F
GPS: match is: 1 | 5 matches
GPS: match #0: GPRMC,164548.00,A,4851.85459,N,00226.22224,E
GPS: match #1: 4851.85459
GPS: match #2: N
GPS: match #3: 00226.22224
GPS: match #4: E
GPS: match is: latitude:48.864243 | longitude: 2.437037
GPS: end of processing

代码:

#include <iostream>
#include <regex>

/// @brief Returns the 01131.324 (Longitude 11 deg 31.324') coordinate as a
/// float
/// @param sReading The string of the coordinate
/// @return the float version
float latitudeDeegresToFloat(char const *sReading) {
  char sDegrees[2 + 1] = {sReading[0], sReading[1], 0};
  float degrees = (float)strtod(sDegrees, NULL);
  float minutes = (float)strtod(sReading + 2, NULL);
  const float latitude = degrees + minutes / 60.0;

  return latitude;
}

/// @brief Returns the 11131.324 longitude (111 deg 31.324') coordinate as a
/// float
/// @param sReading The string of the coordinate
/// @return The float version
float longitudeDeegresToFloat(char const *sReading) {
  char sDegrees[3 + 1] = {sReading[0], sReading[1], sReading[2], 0};
  float degrees = (float)strtod(sDegrees, NULL);
  float minutes = (float)strtod(sReading + 3, NULL);
  const float longitude = degrees + minutes / 60.0;

  return longitude;
}

int main() {
  float latitude, longitude;

  printf("GPS: probably data\n");

  /// Regex string match
  std::smatch match;

  char buffer[256 * 4] = "$GPGLL,4851.87109,N,00226.20521,E,092741.00,A,A*6D";

  printf("GPS: %s\n", buffer);
  bool found = false;

// == Is is a GPGLL message Geographic Acquisition
#define COMMAND "$GPGGA"
  if (strncmp(buffer, COMMAND, sizeof COMMAND - 1) == 0) {

    //$GPGGA,123519,4807.038,N,01131.324,E,
    std::string str(buffer + 1); // Skip leading $
    std::regex rgx("GPGGA,[^,]*,([0-9\\.+-]+),(N|S),([0-9\\.+-]*),(E|W)\\.?");
    found = std::regex_search(str, match, rgx);
  }
  // == Is is a GPGLL message Geographic Latitude Longitude
#define COMMAND "$GPGLL"
  else if (strncmp(buffer, COMMAND, sizeof COMMAND - 1) == 0) {

    std::string str(buffer + 1); // Skip leading $
    std::regex rgx("GPGLL,([0-9\\.+-]+),(N|S),([0-9\\.+-]*),(E|W)\\.?");
    found = std::regex_search(str, match, rgx);
  }

// == Is is a GPRMC message (lat, long)
#define GPRMC "$GPRMC"
  else if (strncmp(buffer, GPRMC, sizeof GPRMC - 1) == 0) {
    std::string str(buffer + 1); // Skip leading $
    std::regex rgx("GPRMC,[^,]*,A,([0-9\\.+-]+),(N|S),([0-9\\.+-]*),(W|E)\\.?");
    found = std::regex_search(str, match, rgx);

  } else {
    printf("GPS: not a message to process but '%s'\n", buffer);
    return 3;
  }

  printf("GPS: match is: %d | %d matches\n", found, match.size());
  if (!found)
    return 1;

  int i = 0;

  for (auto m : match) {
    printf("GPS: match #%d: %x | buffer: %x\n", i, m.str().c_str(), buffer);
    printf("GPS: match #%d: %s\n", i, m.str().c_str());

    switch (i) {
    // Latitude
    case 1:
      latitude = latitudeDeegresToFloat(m.str().c_str());
      break;
    // Latitude direction
    case 2:
      if (m.str().compare("S") == 0)
        latitude = -latitude;
      break;
    // Longitude
    case 3:
      longitude = longitudeDeegresToFloat(m.str().c_str());
      break;
    case 4:
      if (m.str().compare("W") == 0)
        longitude = -longitude;
      break;
    }

    i++;
  }
  printf("GPS: match is: latitude:%f | longitude: %f\n", latitude, longitude);

  // == End of GPS processing
EndOfGpsProcessing:
  printf("GPS: end of processing\n");

  if (latitude == 0 && longitude == 0) {
    printf("GPS: won't publish Null Island\n");
    return 2;
  }

  return 0;
}

这里是一个可以使用的replit:https://replit.com/@Stephanede/GPS-regex

c++ regex gps nmea
1个回答
3
投票

std::match_results
(这就是你的
std::smatch
实际上是什么)的文档解释了发生了什么:

因为 std::match_results 保存 std::sub_matches,其中每个都是匹配的原始字符序列的一对迭代器,所以检查 std::match_results 是否原始字符序列被破坏或它的迭代器被破坏是未定义的行为因其他原因无效。

您传递给

str
std::regex_search
必须
match
更长寿,但事实并非如此。

实际上,您可以完全取消

str
,只需调用
regex_search(buffer, match, rx)
即可。 或者,创建一个将
std::string_view
包裹在顶层的
buffer
或将
str
提升到函数的顶层。

© www.soinside.com 2019 - 2024. All rights reserved.