2

I would like to check the following:

  1. If the last character appended to the stringstream is a comma.
  2. If it is remove it.

std::stringstream str;
str << "["
//loop which adds several strings separated by commas

str.seekp(-1, str.cur); // this is to remove the last comma before closing bracket

str<< "]";

The problem is if nothing is added in the loop, the opening bracket is removed from the string. So I need a way to check whether the last character is a comma. I did that like this:

if (str.str().substr(str.str().length() - 1) == ",")
{
    str.seekp(-1, rteStr.cur);
}

But I don't feel very good about this. Is there a better way to do this?

About the loop:

Loop is used to tokenize a set of commands received through sockets and format it to send to another program through another socket. Each command ends with an OVER flag.

std::regex tok_pat("[^\\[\\\",\\]]+");
std::sregex_token_iterator tok_it(command.begin(), command.end(), tok_pat);
std::sregex_token_iterator tok_end;
std::string baseStr = tok_end == ++tok_it ? "" : std::string(*tok_it);
while (baseStr == "OVER")
{
    //extract command parameters
    str << "extracted_parameters" << ","
}
Jason
  • 2,278
  • 2
  • 17
  • 25
itsyahani
  • 408
  • 3
  • 13
  • I suspect it might be easier to work on not adding the final comma in the first place. – Galik Mar 08 '16 at 04:28
  • There's a question on SO somewhere about adding items in a loop separated by a comma, and not adding a comma to the last item. Edit: possibly [this](http://stackoverflow.com/questions/3496982/printing-lists-with-commas-c) – Tas Mar 08 '16 at 04:38
  • 1
    Just loop over the total number of strings - 1, adding a comma after each string, and after the loop add the last string. If there is no or one string then skip the loop. – Jonny Henly Mar 08 '16 at 04:41
  • The thing is, my strings come from a sregex_token_iterator and I'm using a while loop to detect the token end. There's no way to know how many strings are gonna be there. – itsyahani Mar 08 '16 at 04:48

1 Answers1

7

The way I often deal with these loops where you want to put something like a space or a comma between a list of items is like this:

int main()
{
    // initially the separator is empty
    auto sep = "";

    for(int i = 0; i < 5; ++i)
    {
        std::cout << sep << i;
        sep = ", "; // make the separator a comma after first item
    }
}

Output:

0, 1, 2, 3, 4

If you want to make it more speed efficient you can output the first item using an if() before entering the loop to output the rest of the items like this:

int main()
{
    int n;

    std::cin >> n;

    int i = 0;

    if(i < n) // check for no output
        std::cout << i;

    for(++i; i < n; ++i) // rest of the output (if any)
        std::cout << ", " << i; // separate these
}

In your situation the first solution could work like this:

    std::regex tok_pat("[^\\[\\\",\\]]+");
    std::sregex_token_iterator tok_it(command.begin(), command.end(), tok_pat);
    std::sregex_token_iterator tok_end;
    std::string baseStr = tok_end == ++tok_it ? "" : std::string(*tok_it);

    auto sep = ""; // empty separator for first item

    while (baseStr == "OVER")
    {
        // extract command parameters
        str << sep << "extracted_parameters";
        sep = ","; // make it a comma after first item
    }

And the second (possibly more time efficient) solution:

    std::regex tok_pat("[^\\[\\\",\\]]+");
    std::sregex_token_iterator tok_it(command.begin(), command.end(), tok_pat);
    std::sregex_token_iterator tok_end;
    std::string baseStr = tok_end == ++tok_it ? "" : std::string(*tok_it);

    if (baseStr == "OVER")
    {
        // extract command parameters
        str << "extracted_parameters";
    }

    while (baseStr == "OVER")
    {
        // extract command parameters
        str << "," << "extracted_parameters"; // add a comma after first item
    }
Galik
  • 47,303
  • 4
  • 80
  • 117
  • The thing is, my strings come from a sregex_token_iterator and I'm using a while loop to detect the token end. There's no way to know how many strings are gonna be there. – itsyahani Mar 08 '16 at 04:48
  • @itsyahani I see. Well it still seems like a lot of work to extract the comma if inserting the comma can be avoided in the first place. Can you post more about the loop in the question so maybe someone can come up with a more appropriate solution to mine? – Galik Mar 08 '16 at 04:57
  • @itsyahani I have added my first solution to your example code to show how it can be used in your situation. – Galik Mar 08 '16 at 05:14
  • @itsyahani And now I added the possibly slightly faster second solution. – Galik Mar 08 '16 at 05:18