0

I have a text file with GCode commands. When I encounter a specific command, I want to place a new line after it with a new command. That part is not an issue. The issue I have is that the command has the following form G0/G1 Xnnn Ynnn Znnn where the X/Y/Z params may or may not be present (at least one is required, but not all). What I want are the numbers after the X/Y/Z. My current working solution would involve using substring(start + 1, end - 1) and find(X/Y/Z), then checking for all combinations as:

size_t xPos = str.find("X");
size_t yPos = str.find("Y");
size_t zPos = str.find("Z");
float x, y, z;
if(xPos != std::string::npos && yPos != std::string::npos) 
    x = std:stof(str.substring(xPos + 1, yPos - 1);

Is this an appropriate method of doing this? Am I overcomplicating things?

Edit: So, an input would look like G0 X101.1 Y102.3 or G0 Y122 or G0 X55 Z123, so the n refers to a digit and the command is to tell something like a 3D printer how many units to move in a given direction, so it may need to make a move in one, two, or three directions.

4
  • 1
    Look into regular expressions. Commented Apr 18, 2018 at 20:20
  • What is nnn? Can it contain the letters X/Y/Z? Cant you simply find the next whitespace afterxPos ? Commented Apr 18, 2018 at 20:20
  • Can you give several actual input examples? Commented Apr 18, 2018 at 20:38
  • See Spirit-based solution for your updated question in my updated answer. Commented Apr 19, 2018 at 10:48

2 Answers 2

2

Each time I need to parse something in C++, I consider using Boost.Spirit. It is suitable for both trivial and quite complex parsing tasks.

With Boost.Spirit, it would look like this:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <string>
#include <vector>

int main()
{
  namespace qi = boost::spirit::qi;
  namespace ascii = boost::spirit::ascii;
  std::string input = "G0/G1 X001 Y123 Z321";
  int x, y, z;
  bool result = qi::phrase_parse(input.begin(), input.end(),
     qi::lit("G0/G1") >> "X" >> qi::int_ >> "Y" >> qi::int_ >> "Z" >> qi::int_ , ascii::space, x, y, z);
  if (result)
  {
      std::cout << "X:" << x << std::endl;
      std::cout << "Y:" << y << std::endl;
      std::cout << "Z:" << z << std::endl;
  }
}

Note that the coordinates are parsed directly into ints!

UPDATE: A bit more complicated parsing, according to your updated question:

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <string>
#include <vector>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>

int main()
{
  namespace qi = boost::spirit::qi;
  namespace ascii = boost::spirit::ascii;
  std::string input = "G0 X001 Z321";
  boost::optional<float> x, y, z;
  int cmd;
  using namespace qi;
  bool result = phrase_parse(input.begin(), input.end(), qi::lexeme[lit("G") >> int_] >> -(lit("X") >> float_) >> -(lit("Y") >> float_) >> -(lit("Z") >> float_) , ascii::space, cmd, x, y, z);
  if (result)
  {
      std::cout << "Command number:" << cmd << std::endl;
      std::cout << "X:" << x << std::endl;
      std::cout << "Y:" << y << std::endl;
      std::cout << "Z:" << z << std::endl;
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

This looks to be an appropriate solution. However, my IDE (CLION) is complaining that qi::lit expects two arguments. Looking at the docs, that doesn't seem to be the case. Have you ever encountered an issue like that?
@JohnT well, the static analysis of c++ code is not a simple task, especially when it comes to modern, extensivly templated code. Try upgrading CLion, they're constantly improving it.
1

Using std::stringstream

int x, y, z = -1;

std::stringstream ss("G0/G1 X123 Y456");
std::string str;
while (ss>>str) {
    if (str.at(0) == 'X') {
        std::stringstream(str.substr(1)) >> x;
    } else if (str.at(0) == 'Y') {
        std::stringstream(str.substr(1)) >> y;
    } else if (str.at(0) == 'Z') {
        std::stringstream(str.substr(1)) >> z;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.