-1

I've created a program that splits a string into, well, more strings, based around a . So, for instance, say I input the string

Workspace.SiteNet.Character.Humanoid

it is SUPPOSED to print

Workspace
SiteNet
Character
Humanoid

However, it prints

Workspace
SiteNet.Character
Character.Humanoid
Humanoid

This is the code.

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <vector>
#include <sstream>
#include <WinInet.h>
#include <fstream>
#include <istream>
#include <iterator>
#include <algorithm>
#include <string>
#include <Psapi.h>
#include <tlhelp32.h>


int main() {
  std::string str;
  std::cin >> str;
  std::size_t pos = 0, tmp;
  std::vector<std::string> values;
  while ((tmp = str.find('.', pos)) != std::string::npos) {
    values.push_back(str.substr(pos, tmp));
    pos = tmp + 1;
  }
  values.push_back(str.substr(pos, tmp));

  for (pos = 0; pos < values.size(); ++pos){
    std::cout << "String part " << pos << " is " << values[pos] << std::endl;
  }
  Sleep(5000);
}
Shawn Mehan
  • 4,513
  • 9
  • 31
  • 51
J Doe
  • 39
  • 5
  • 2
    What do you see when you debug it? – zmbq Dec 28 '15 at 05:54
  • 2
    You could try adding `std::cout << "pos " << pos << ", tmp " << tmp << '\n';` inside your while loop and working out which values are wrong, then it might be obvious why they're wrong and how to fix it. Second - check the meaning of the arguments to [`substr`](http://en.cppreference.com/w/cpp/string/basic_string/substr). – Tony Delroy Dec 28 '15 at 05:55
  • If I input "Workspace.SiteNet.Character.Humanoid", I'll see " "Workspace" "SiteNet.Character" "Character.Humanoid" "Humanoid"" @zmbq – J Doe Dec 28 '15 at 05:55
  • 1
    You could actually use [`std::getline`](http://en.cppreference.com/w/cpp/string/basic_string/getline) for this, it can use any separator character and not only newline. It would also require less code and be easier. – Some programmer dude Dec 28 '15 at 05:58
  • 5
    Duplicate post of [this](http://stackoverflow.com/questions/34487014/defining-variables-from-split-strings/34487146#34487146) – ChrisD Dec 28 '15 at 06:02
  • These are two completely different questions @ChrisD – J Doe Dec 28 '15 at 06:02
  • 4
    @JDoe: *how* exactly are they "completely different"? - even looks like you copied and pasted the accepted (but buggy) "solution" from that very page, which seems a pretty clear acknowledgement that it's a duplicate. – Tony Delroy Dec 28 '15 at 06:07

2 Answers2

6

Your problem is the arguments you pass to str.substr

string::substr takes two arguments: the start position, and the length of the substring to extract.

std::vector<std::string> split_string(const string& str){
    std::vector<std::string> values;
    size_t pos(0), tmp;
    while ((tmp = str.find('.',pos)) != std::string::npos){
        values.push_back(str.substr(pos,tmp-pos));
        pos = tmp+1;
    }
    if (pos < str.length())  // avoid adding "" to values if '.' is last character in str
        values.push_back(str.substr(pos));
    return values;
}
Timothy Murphy
  • 1,322
  • 8
  • 16
1

I think it would be easier to find the last dot in s, push the substring of everything after the dot into the vector, then make s everything before the last dot. Repeat this until there are no dots, then push s into the vector.

Here's how that can be accomplished:

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

std::vector<std::string> split_at_dot(std::string& s) {
  std::vector<std::string> matches;
  size_t pos;
  // while we can find the last dot
  while((pos = s.find_last_of(".")) != -1) {
    // push back everything after the dot
    matches.push_back(s.substr(pos+1));
    // update s to be everything before the dot
    s = s.substr(0, pos);
  }
  // there are no more dots - push back the rest of the string
  matches.push_back(s);
  // return the matches
  return matches;
}

int main() {
  std::string s = "Workspace.SiteNet.Character.Humanoid";
  std::vector<std::string> matches = split_at_dot(s);
  for(auto match: matches) {
    std::cout << match << std::endl;
  }
}

When I run it on your input, I get:

Humanoid
Character
SiteNet
Workspace

Notice that this will give you your expected answers in reverse. If it's really important that you get them in that order you can use a std::stack or simply reverse the std::vector after calling the function.

erip
  • 16,374
  • 11
  • 66
  • 121