C++ 解析文本和输出“;“出现时间”;某些行的

C++ 解析文本和输出“;“出现时间”;某些行的,c++,string,parsing,C++,String,Parsing,所以我得到的文件看起来像: $GPGGA,124613.90,5543.3221231,N,03739.1368442,E,1,15,0.69,147.0851,M,14.4298,M,,*54 $GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,44,02,11,268,44*7E $GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71 $GPGSV,3,3,10,

所以我得到的文件看起来像:

$GPGGA,124613.90,5543.3221231,N,03739.1368442,E,1,15,0.69,147.0851,M,14.4298,M,,*54
$GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,44,02,11,268,44*7E
$GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71
$GPGSV,3,3,10,23,30,116,46,04,37,114,47*79
$GLGSV,2,1,07,84,17,338,43,78,15,212,48,85,12,032,46,67,84,223,53*67
$GLGSV,2,2,07,77,67,195,47,76,50,047,54,66,32,144,52*5C
$GPGGA,124614.00,5543.3221239,N,03739.1368445,E,1,15,0.69,147.0864,M,14.4298,M,,*53
$GPGSV,3,1,10,27,12,078,41,05,31,308,49,16,25,043,43,02,11,268,44*79
$GPGSV,3,2,10,26,03,031,39,07,74,216,52,09,58,121,52,30,39,234,48*71
$GPGSV,3,3,10,23,30,116,46,04,37,114,47*79
$GLGSV,2,1,07,84,17,338,43,78,15,212,48,85,12,032,46,67,84,223,53*67
$GLGSV,2,2,07,77,67,195,47,76,50,047,54,66,32,144,52*5C
我的cod正在检查字符串的校验和,并在字符串中输出一些值。 在$GPGGA中,“124614.00”是时间。12小时46分14秒。我需要输出时间的“外观”$GPGSV线。我试着用指针减去第一个值和后面的值,但我一定是把什么地方搞砸了

#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <numeric>
#include <cstdlib>
#include <cstring>
#include <stdio.h>

int checksum(const char* s) {
  int c = 0;

  while (*s)
    c ^= *s++;

  return c;
}

int main() {
  char linec_h[200];
  int k, key;
  int* hour = NULL;
  int* minute = NULL;
  float* sec = NULL;
  std::string line, key_s;

  std::ifstream logs_("C:/Users/Olya/Desktop/broken.txt");
  std::ofstream pout("C:/Users/Olya/Desktop/outLOG.txt");

  if (logs_.is_open()) {
    while (getline(logs_, line)) {
      key_s = line.substr(line.length() - 2, 2);
      key = strtol(key_s.c_str(), NULL, 16);

      line = line.substr(1, line.length() - 4);
      strcpy_s(linec_h, line.c_str());
      if (key != checksum(linec_h))
        pout << "Line is corrupted!" << std::endl;
      else {
        k = 0;
        if (line.substr(0, 5) == "GPGGA") {
          if (hour, minute, sec) {
            *hour = stoi(line.substr(5, 2)) - *hour;
            *minute = stoi(line.substr(7, 2)) - *minute;
            *sec = stof(line.substr(9, 4)) - *sec;
          }

          else {
            hour = new int;
            minute = new int;
            sec = new float;
            *hour = stoi(line.substr(5, 2));
            *minute = stoi(line.substr(7, 2));
            *sec = stof(line.substr(9, 4));
          }

        } else if (line.substr(0, 5) == "GPGSV") {
          for (size_t i = 0, SNR = 7, N = 4; i < line.size(); i++) {
            if (line[i] == ',')
              k++;
            if (k == N) {
              pout << "Satellite number -- " << line.substr(i + 1, 2) << "  ";
              if ((N += 4) > 16)
                ;
            } else if (k == SNR) {
              pout << "SNR -- " << line.substr(i + 1, 2) << "  time -- " << hour
                   << "." << minute << "." << sec << std::endl;
              if ((SNR += 4) > 19)
                break;
            }
          }
        }
      }
      delete hour;
      delete minute;
      delete sec;
    }
    logs_.close();
    std::cout << "Success" << std::endl;
  } else
    std::cout << "File is not open" << '\n';
  pout.close();

  return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
整数校验和(常量字符*s){
int c=0;
而(*s)
c^=*s++;
返回c;
}
int main(){
char linec_h[200];
int k,键;
int*hour=NULL;
int*minute=NULL;
浮点*秒=空;
标准::字符串行,键;
std::ifstream日志(“C:/Users/Olya/Desktop/break.txt”);
std::of stream pout(“C:/Users/Olya/Desktop/outLOG.txt”);
如果(日志是打开的()){
while(getline(logs,line)){
key_s=line.substr(line.length()-2,2);
key=strtol(key_s.c_str(),NULL,16);
line=line.substr(1,line.length()-4);
strcpy_s(linec_h,line.c_str());
if(key!=校验和(linec_h))

pout我可以看到像
if(小时、分钟、秒){
这样的错误,还有许多C风格的代码,用指针操作。我不想调试你的代码

作为对您的samll提示,我创建了一个解析器,它读取所有源代码行,将tem拆分为标记并检查校验和

只需要几行代码就可以了。从那以后,您可以进一步开发

#include <iostream>
#include <regex>
#include <vector>
#include <iterator>
#include <string>
#include <utility>
#include <algorithm>
#include <functional>
#include <numeric>
#include <fstream>

const std::regex re{ R"(\$(.*)\*[abcdefABCDEF\d]{2})" };
const std::regex delimiter{ "," };
using Tokens = std::vector<std::string>;


std::tuple<bool, Tokens> checkString(const std::string& str) {

    // Return value of the function. Assume that string is not ok
    std::tuple<bool, std::vector<std::string>> result(false, {});

    // We want to find a string in the given format
    std::smatch sm{};
    if (std::regex_match(str, sm, re)) {

        // OK, found. Validate checksum
        if (std::string s = sm[1]; std::stoul(str.substr(str.size() - 2), nullptr, 16) == std::accumulate(s.begin(), s.end(), 0U, std::bit_xor<unsigned char>())) {

            // Tokenize string
            Tokens tokens(std::sregex_token_iterator(str.begin(), str.end(), delimiter, -1), {});
            // Build return value
            result = std::make_tuple(true, std::move(tokens));
        }
    }
    return result;
}

int main() {

    std::vector<Tokens> csvData{};

    // Open file and check if it is open
    if (std::ifstream logs("r:\\log.txt"); logs) {

        // Read all lines of files
        for (std::string line{}; std::getline(logs, line);) {
            if (const auto& [ok, data] = checkString(line); ok) {
                csvData.push_back(std::move(data));
            }
            else {
                std::cerr << "**** Coruppted: " << line << "\n";
            }
        }
    }

    // So, now we have read all csv data
    // Show eight column of GPGSV data
    for (const Tokens& t : csvData) {
        if (t[0] == "$GPGGA") {
            std::cout << "$GPGGA  -->" << t[1] << "\n";
        }
        else if (t[0] == "$GPGSV") {
            std::cout << "$GPGSV  -->" << t[4] << " " << t[7] << "\n";
        }
    }
    return 0;
}

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
const std::regex re{R“(\$(.*)\*[abcdefABCDEF\d]{2})”;
常量std::regex分隔符{“,”};
使用Tokens=std::vector;
std::tuple checkString(const std::string和str){
//函数的返回值。假设字符串不正常
std::tuple result(false,{});
//我们希望找到给定格式的字符串
std::smatch sm{};
if(std::regex_匹配(str、sm、re)){
//好的,找到了。验证校验和
if(std::string s=sm[1];std::stoul(str.substr(str.size()-2),nullptr,16)=std::accumulate(s.begin(),s.end(),0U,std::bit_xor()){
//标记化字符串
Tokens Tokens(std::sregx_token_迭代器(str.begin(),str.end(),delimiter,-1),{});
//构建返回值
结果=std::make_tuple(true,std::move(tokens));
}
}
返回结果;
}
int main(){
std::vector csvData{};
//打开文件并检查它是否已打开
if(std::ifstream日志(“r:\\log.txt”);日志){
//读取所有文件行
for(std::string line{};std::getline(logs,line);){
如果(常量自动&[ok,数据]=检查字符串(行);ok){
csvData.push_back(标准::移动(数据));
}
否则{

std::cerr只是为了好玩。我创建了一个完整的解决方案,可以完全解析GPS NMEA格式,并将所有结果放入结构中。因此,您可以获得所有卫星数据

但是,我只显示您在示例中使用的值

我把我的编码风格改成了你的。在C++中,我会把事情做得完全不同。无论如何。< /P> 请参阅附件中的完整示例:

#include <string>
#include <ctime>
#include <cstring>
#include <iostream>
#include <fstream>
#include <iomanip>

constexpr size_t NumberOfFixQualityStrings = 9;
constexpr size_t NumberOfSatellitesPerGSVSentencePart = 4;
constexpr size_t MaxNumberOfPartsInSentence = 10;
constexpr size_t MaxTokensInSentence = 64;
constexpr size_t NumberOfFieldsInGGA = 12;

std::string fixQualityString[NumberOfFixQualityStrings]{ 
    "invalid", "GPS fix (SPS)", "DGPS fix", "PPS fix", "Real Time Kinematic", "Float RTK", 
    "estimated (dead reckoning", "Manual input mode", "Simulation mode" };

//  essential fix data which provide 3D location and accuracy data
struct GGA { 
    // Time of last satellite fix
    unsigned int fixTimeInUtcHours{};
    unsigned int fixTimeInUtcMinutes{};
    unsigned int fixTimeInUtcSeconds{};
    unsigned int fixTimeInUtcMilliSeconds{};
    // Position: Lattitude
    unsigned int lattitudeInDegree{};
    double lattitudeInMinutes{};
    std::string lattitideDirection{};
    // Position: Longitude
    unsigned int longitudeInDegree{};
    double longitudeInMinutes{};
    std::string longitudeDirection{};
    // FixQuality // see dteails as string above
    unsigned int fixQuality{};
    std::string fixQualityString{};
    // Number of satellites being tracked (can be more than shown in GSV, not all are beeing used for calculation)
    unsigned int numberOfTrackedSatellites{};
    //  Horizontal dilution of position
    double horizontalDilution{};
    // Altitude, Meters, above mean sea level
    double altitude{};
    std::string altitudeDimension{};
    // Height of geoid (mean sea level) above WGS84 ellipsoid
    double goidHight{};
    std::string goidHightDimension{};
};

// Detail information for satellites in satellit view (GSV)
struct SatelliteData {
    std::string satellitePRNnumber{};
    double elevationInDegress{};
    double azimuthInDegrees{};
    double snr{};  // signal noise ratio
};

// Part of a GSV sentence
struct GSVSentencePart {
    size_t numberOfSentencesForFullData{};
    size_t sentencePartNumber{};
    size_t numberOfSatellitesInView{};
    size_t numberOfSatellitesInThisPart{};
    SatelliteData satelliteData[NumberOfSatellitesPerGSVSentencePart];
};
struct GSV
{
    GSVSentencePart gsvSentencePart[MaxNumberOfPartsInSentence];
    size_t numberOfParts{};
};

bool checksumTest(std::string& line) {
    bool result{ false };
    // Check, if there is a 2 digt checksum at the end and convert it to decimal
    if (size_t pos{}, checkSumGiven{ std::stoul(line.substr(line.size() - 2), &pos, 16) }; pos == 2)
    {
        // Strip off checksum part
        line = line.substr(1,line.size() - 4);
        // Calculate checksum
        unsigned char calculatedChecksum{ 0U }; for (const unsigned char c : line)  calculatedChecksum ^= c;
        // Get result
        result = (calculatedChecksum == checkSumGiven);
    }
    return result;
}

// Split all strings into a tokens
size_t splitIntoTokens(std::string& s, std::string (&tokens)[MaxTokensInSentence]) {
    // Number of converted tokens
    size_t numberOfTokens{ 0 };
    // First check checksum
    if (checksumTest(s)) {
        // Now split along each comma
        for (size_t i{ 0U }, startpos{ 0U }; i < s.size(); ++i) {
            // So, if there is a comma or the end of the string
            if ((s[i] == ',') || (i == (s.size() - 1))) {
                // Copy substring
                tokens[numberOfTokens++] = s.substr(startpos, i - startpos);
                startpos = i + 1;
            }
        }
    }
    return numberOfTokens;
}


GGA convertStringToGGA(std::string& s) {
    GGA gga; 
    // Split string into tokens and check, if it worked
    if (std::string tokens[MaxTokensInSentence]; splitIntoTokens(s, tokens) > NumberOfFieldsInGGA && tokens[0] == "GPGGA") {
        gga.fixTimeInUtcHours = std::stoul(tokens[1].substr(0, 2));
        gga.fixTimeInUtcMinutes = std::stoul(tokens[1].substr(2, 2));
        gga.fixTimeInUtcSeconds = std::stoul(tokens[1].substr(4, 2));
        gga.fixTimeInUtcMilliSeconds = std::stod(tokens[1].substr(6, 2))*1000.0;
        gga.lattitudeInDegree = std::stoul(tokens[2].substr(0, 2));
        gga.lattitudeInMinutes = std::stod(tokens[2].substr(2));
        gga.lattitideDirection = tokens[3];
        gga.longitudeInDegree = std::stoul(tokens[4].substr(0, 2));
        gga.longitudeInMinutes = std::stod(tokens[4].substr(2));
        gga.longitudeDirection = tokens[5];
        gga.fixQuality = std::stoul(tokens[6]);
        gga.fixQualityString = (gga.fixQuality < NumberOfFixQualityStrings) ? fixQualityString[gga.fixQuality] : fixQualityString[0];
        gga.numberOfTrackedSatellites = std::stoul(tokens[7]);
        gga.horizontalDilution = std::stod(tokens[8]);
        gga.altitude = std::stod(tokens[9]);
        gga.altitudeDimension = tokens[10];
        gga.goidHight = std::stod(tokens[11]);
        gga.goidHightDimension = tokens[12];
    }
    return gga;
}

GSVSentencePart convertToGSVSentencePart(std::string& s) {
    GSVSentencePart gsvsp;
    // Split string into tokens and check, if it worked
    std::string tokens[MaxTokensInSentence];
    if (size_t numberOfCOnvertedTokens = splitIntoTokens(s, tokens); numberOfCOnvertedTokens > 0 && tokens[0] == "GPGSV") {
        gsvsp.numberOfSentencesForFullData = std::stoul(tokens[1]);
        gsvsp.sentencePartNumber = std::stoul(tokens[2]);
        gsvsp.numberOfSatellitesInView = std::stoul(tokens[3]);
        gsvsp.numberOfSatellitesInThisPart = 0;
        for (size_t currentToken = 4; currentToken < numberOfCOnvertedTokens; currentToken += 4) {
            gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].satellitePRNnumber = tokens[currentToken];
            gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].elevationInDegress = stod(tokens[currentToken + 1]);
            gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].azimuthInDegrees= stod(tokens[currentToken + 2]);
            gsvsp.satelliteData[gsvsp.numberOfSatellitesInThisPart].snr = stod(tokens[currentToken + 3]);
            ++gsvsp.numberOfSatellitesInThisPart;
        }
    }
    return gsvsp;
}
std::string calculateElapsedTime(const GGA& previousGGA, const GGA& nextGGA) {
    std::tm tmPrevious{}, tmNext{};
    tmPrevious.tm_year = 100; tmPrevious.tm_mon = 1; tmPrevious.tm_mday = 1;
    tmNext.tm_year = 100; tmNext.tm_mon = 1; tmNext.tm_mday = 1;
    tmPrevious.tm_hour = previousGGA.fixTimeInUtcHours;
    tmPrevious.tm_min = previousGGA.fixTimeInUtcMinutes;
    tmPrevious.tm_sec = previousGGA.fixTimeInUtcSeconds;
    std::time_t previousTime = std::mktime(&tmPrevious);
    tmNext.tm_hour = nextGGA.fixTimeInUtcHours;
    tmNext.tm_min = nextGGA.fixTimeInUtcMinutes;
    tmNext.tm_sec = nextGGA.fixTimeInUtcSeconds;
    std::time_t nextTime = std::mktime(&tmNext);
    double diff = std::difftime(nextTime, previousTime);
    diff  = diff + 1.0*nextGGA.fixTimeInUtcMilliSeconds/1000.0- 1.0*previousGGA.fixTimeInUtcMilliSeconds/1000.0;
    return std::to_string(diff);
}

int main() {
    // Open file and check, if it is open
    if (std::ifstream nmeaFile("r:\\log.txt"); nmeaFile) {

        GGA previousGGA;
        GGA nextGGA;
        GSV gsv;
        size_t state{ 0 };
        for (std::string line{}; std::getline(nmeaFile, line); ) {
            switch  ( state) {

            case 0:     // wait for first GGA data
                if (line.substr(0, 6) == "$GPGGA") {

                    previousGGA = nextGGA;
                    nextGGA = convertStringToGGA(line);

                    state = 1;
                    gsv = {};
                }
                break;
            case 1: // wait for GSV
                if (line.substr(0, 6) == "$GPGSV") {
                    gsv.gsvSentencePart[gsv.numberOfParts] = convertToGSVSentencePart(line);
                    if (gsv.gsvSentencePart[gsv.numberOfParts].numberOfSentencesForFullData ==
                        gsv.gsvSentencePart[gsv.numberOfParts].sentencePartNumber) {
                        state = 0;
                        ++gsv.numberOfParts;
                        // Now all data are available in reable and structed format.
                        // You can do, what you want with them
                        // For example, we can print all Satellite Data:
                        size_t counter{ 0 };
                        for (size_t i = 0; i < gsv.numberOfParts; ++i) {
                            for (size_t j = 0; j < gsv.gsvSentencePart[i].numberOfSatellitesInThisPart; j++) {
                                std::cout << "Satellite: " << std::setw(2) << ++counter << "  Satellite name: " <<
                                    std::setw(3) << gsv.gsvSentencePart[i].satelliteData[j].satellitePRNnumber <<
                                    "   SNR: " << std::setw(8) << gsv.gsvSentencePart[i].satelliteData[j].snr << 
                                    "  Elapsed time: "<< calculateElapsedTime(previousGGA, nextGGA)<< " s\n";
                            }
                        }
                        --gsv.numberOfParts;
                    }
                    ++gsv.numberOfParts;
                }
                break;
            } 
        }
    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
constexpr size\u t NumberOfFixQualityStrings=9;
constexpr size_t NumberOfSatellitesPerGSVSentencePart=4;
constexpr size\u t MaxNumberOfPartsInSession=10;
constexpr size\u t maxTokensinSession=64;
constexpr size_t numberofieldsingga=12;
std::string fixQualityString[NumberOfFixQualityStrings]{
“无效”、“GPS定位(SPS)”、“DGPS定位”、“PPS定位”、“实时运动学”、“浮动RTK”,
“估计(航位推算”、“手动输入模式”、“模拟模式”};
//提供3D位置和精度数据的基本固定数据
结构GGA{
//最后一次卫星定位时间
无符号int-fixTimeInUtcHours{};
无符号int-fixtimeinutcmins{};
无符号int-fixtimeinutseconds{};
无符号int-fixtimeinutcmissions{};
//职位:Lattude
无符号int-latticudeindegree{};
双格点{};
std::string latitidedirection{};
//位置:经度
无符号int-longitudeInDegree{};
双纵联{}分钟;
std::string longitudeDirection{};
//FixQuality//请参见上面的dteails字符串
无符号整型质量{};
std::string fixQualityString{};
//正在跟踪的卫星数量(可能超过GSV中显示的数量,并非所有卫星都用于计算)
无符号整数跟踪卫星{};
//位置的水平稀释
双水平稀释{};
//海拔高度,米,高于平均海平面
双高度{};
std::字符串altitudeDimension{};
//WGS84椭球体上方大地水准面高度(平均海平面)
双甲状腺右{};
std::字符串goidHightDimension{};
};
//卫星视图(GSV)中卫星的详细信息
结构卫星数据{
std::字符串卫星号{};
双提升指数{};
双方位角角度{};
双信噪比{};//信噪比
};
//GSV语句的一部分
结构GSVSentencePart{
完整数据{}的大小和数量;
尺寸句子零件号{};
卫星在视图{}中的大小和数量;
该部分{}中卫星的大小和数量;
卫星数据卫星数据[卫星数/卫星数/分件];
};
结构GSV
{
GSVSentencePart GSVSentencePart[句子中的最大零件数];
零件的尺寸和数量{};
};
布尔校验集测试(标准::字符串和行){
bool结果{false};
//检查末尾是否有2位校验和,并将其转换为十进制
if(size_t pos{},checksum{std::stoul(line.substr(line.size()-2),&pos,16)};pos==2)
{
//去掉校验和部分
line=line.substr(1,line.size()-4);
//计算校验和
无符号字符calculatedChecksum{0U};for(const unsigned char c:line)calculatedChecksum^=