-4

I have converted a few numbers to a string with a separator from type of string as follows

#include <sstream>
#include <string>
#include <iostream>

std::string vars_to_string(std::string separator, double object_x, double object_y, double object_z, std::string msg) {
  std::stringstream ss;
  ss << msg << separator;
  ss << object_x << separator;
  ss << object_y << separator;
  ss << object_z;
  return ss.str();
}

void string_to_vars(std::string text, std::string separator, double &object_x, double &object_y, double &object_z, std::string &msg) {
  // ????????
}

int main() {
  double x = 4.2, y = 3.7, z = 851;
  std::string msg = "position:";
  std::string text = vars_to_string("__%$#@!__", x, y, z, msg);
  std::cout << text << std::endl;

  double rx, ry, rz;
  std::string rmsg;
  string_to_vars(text, "__%$#@!__", rx, ry, rz, rmsg);
  std::cout << "Retrived data: " << rx << ", " << ry << ", " << rz << ", " << rmsg << std::endl;
  return 0;
}

Now, I wonder how I can do the reverse to convert the result variable into msg, object_x, object_y, object_z again?

To stop suggesting trivial solutions I use __%$#@!__ as a separator. The separator is decided by the user and it can be any arbitrary value and the code should not fail.

I do not make assumption that object_x is pure digits. I only assume that it does not contain the separator.

We do not know the separator.

Is there any simple solution without using Boost?

glennsl
  • 28,186
  • 12
  • 57
  • 75
ar2015
  • 5,558
  • 8
  • 53
  • 110
  • 2
    `std::getline()` allows to specify _"unknown separators"_. And why do you believe someone hates you? Do you need a hang out with a psychologist? – user0042 Sep 14 '17 at 12:53
  • You can deduce the separator by working backwards. If you know the string ends with then you can walk backwards on the string and derive get the separator string. Then use that to tokenize the input string and convert the last three values to double. – Rob Sep 14 '17 at 12:56
  • @user0042, thanks a lot. How should I use it? I get errors here in [wonderbox](https://wandbox.org/permlink/Ktbl19nnTLlh2Njm). – ar2015 Sep 14 '17 at 12:57
  • @ar2015 _"How should I use it? "_ Best as mentioned in the [documentation](http://en.cppreference.com/w/cpp/string/basic_string/getline). [Here](https://stackoverflow.com/questions/23047052/why-does-reading-a-record-struct-fields-from-stdistream-fail-and-how-can-i-fi) are some more sophisticated tips how to handle that using custom I/O manipulators. Don't ask XY problems, insisting that your approach will be the right one, do more research. – user0042 Sep 14 '17 at 13:01
  • @user0042, I receive an error because my separator is a string not a character. – ar2015 Sep 14 '17 at 13:01
  • 2
    @ar2015 `std::string::find()` allows you to specify multiple separators with a string. – user0042 Sep 14 '17 at 13:03
  • @user0042, can I use `find` on a stream? – ar2015 Sep 14 '17 at 13:05
  • Invert the string so the characters are in reverse order. then walk the string till you find three matching strings that are separated by valid inverted double strings. that will give you the separator.. You should be able to do this with a regex. – Rob Sep 14 '17 at 13:05
  • @ar2015 You can use it with a `std::string`. Probably you should give up upon finding the _easiest solution_. Go with working solutions rather. – user0042 Sep 14 '17 at 13:07
  • What re the restrictions on the separator? Can it be a string with the value `"1"`? If so there is no solution. – Chad Sep 14 '17 at 13:08
  • @user0042, Thanks a lot. That is what I was going to make sure about (whether there is a simple solution.). – ar2015 Sep 14 '17 at 13:09
  • What happens when your separator is also contained in the msg string? Your requirements make your problem much harder to solve for no apparent reason. – Retired Ninja Sep 14 '17 at 13:09
  • @Chad, it is undefined behavior. You can interpret `5551666` as either one number or two numbers separated by `1`. – ar2015 Sep 14 '17 at 13:10
  • There is no "_one size fits all_" with the stringstream. You need to roll out your own solution, go with regex or explore 3rd party libraries. – Ron Sep 14 '17 at 13:11
  • @ar2015 Well, I always try to find working solutions in 1st place. I don't bother much about _elegance_ or such. It will make your code harder to maintain for anyone else anyways. – user0042 Sep 14 '17 at 13:11
  • Thanks user0042, Ron, Chad, Retired Ninja, The fact that I have understood there is no straight forward solution, is a big achievement for me. – ar2015 Sep 14 '17 at 13:12

1 Answers1

1

May I suggest you this piece of code?

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

using namespace std;

void dtokenize(const std::string& str, std::vector<std::string>& tokens, const std::string& separator)
{
    std::string::size_type pos = 0;
    std::string::size_type lastPos = 0;

    while(std::string::npos != pos) {
        // find separator
        pos = str.find(separator, lastPos);

        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));

        // set lastpos
        lastPos = pos + separator.size();
    }
}

std::string vars_to_string(std::string separator,double object_x, double object_y, double object_z, std::string msg)
{
    std::stringstream ss;
    ss<<msg<<separator;
    ss<<object_x<<separator;
    ss<<object_y<<separator;
    ss<<object_z;
    return ss.str();
}

void string_to_vars(std::string text,std::string separator,double &object_x, double &object_y, double &object_z, std::string &msg)
{
    vector<string> vars;
    dtokenize(text, vars, separator);

    if(vars.size() == 4) {
        msg = vars[0];
        object_x = stod(vars[1]);
        object_y = stod(vars[2]);
        object_z = stod(vars[3]);
    }
}

int main()
{
    double x=4.2,y=3.7,z=851;
    std::string msg="position:";
    std::string text=vars_to_string("__%$#@!__",x,y,z,msg);
    std::cout<<text<<std::endl;

    double rx,ry,rz;
    std::string rmsg;
    string_to_vars(text,"__%$#@!__",rx,ry,rz,rmsg);
    std::cout<<"Retrived data: "<<rx<<", "<<ry<<", "<<rz<<", "<<rmsg<<std::endl;

    return 0;
}
Danilo Carrabino
  • 397
  • 6
  • 12