strtok() analogue in C++ - c++

I just can't find an algorithm to split the string into words by numerous delimiters. I know how to split a string by whitespace with istringtream and by single delimiter with getline. How can I connect them all.
For instance:
input: This -is-a!,string;
output:
This
is
a
string

Why not just #include <cstring> and use std::strtok() in your C++ program?

#include <iostream>
#include <string>
#include <vector>
using namespace std;
void SplitToVector(vector<string> &v, string dlm, string src){
string::size_type p, start=0, len=src.length();
v.clear();
start = src.find_first_not_of(dlm);
p = src.find_first_of(dlm, start);
while(p != string::npos){
v.push_back(src.substr(start, p-start));
start = src.find_first_not_of(dlm, p);
p = src.find_first_of(dlm, start);
}
if(len>start)//rest
v.push_back(src.substr(start, len - start));
}
int main(void){
char input[256] = "This -is-a!,string;";
vector<string> v;
int i, size;
SplitToVector(v, "-!,;", input);
//cout << input << endl;
size = v.size();
for(i=0; i<size; i++)
cout << v.at(i) << endl;
return 0;
}

I would recommend split in boost (string algorithm), see http://www.boost.org/doc/libs/1_53_0/doc/html/string_algo/usage.html#idp163440592.

Related

Need to separate numbers from a string on a line, separated by ';', (25;16;67;13) in c++

We have a string (25;16;67;13;14;.......)
We need to print out the numbers separately. The last number does not have a semicolon behind it.
Output should be something like that:
25
16
67
13
14
......
Assuming we are using str.find, str.substr and size_t variables current_pos, prev_pos, what will be the condition of the while loop we are using to browse the line, so that it prints out all the numbers, not just the first one?
You can make use of std::istringstream:
#include <sstream>
#include <iostream>
int main() {
std::string text("25;16;67;13;14");
std::istringstream ss(text);
std::string token;
while(std::getline(ss, token, ';'))
{
std::cout << token << '\n';
}
return 0;
}
Running the above code online results in the following output:
25
16
67
13
14
If you need only to print the numbers in the string (rather than represent them in data structures) the solution is quite easy. Simply read the entire string, then print it character by character. If the character is a semicolon, print a new line instead.
#include <iostream>
#include <string>
using namespace std;
int main(){
string input;
cin >> input;
for(int i = 0; i < input.length(); i++){
if(input.at(i) == ';') cout << endl;
else cout << input.at(i);
}
}
using namespace std;
int main() {
string a{ "1232,12312;21414:231;23231;22" };
for (int i = 0; i < a.size(); i++) {
if (ispunct(a[i])) {
a[i] = ' ';
}
}
stringstream line(a);
string b;
while (getline(line, b, ' ')) {
cout << b << endl;
}
}
//any punctuation ",/;:<>="
I will give you an exact answer to your question with an example and an alternative solution with an one-liner.
Please see
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <regex>
const std::regex re(";");
int main() {
std::string test("25;16;67;13;14;15");
// Solution 1: as requested
{
size_t current_pos{};
size_t prev_pos{};
// Search for the next semicolon
while ((current_pos = test.find(';', prev_pos)) != std::string::npos) {
// Print the resulting value
std::cout << test.substr(prev_pos, current_pos - prev_pos) << "\n";
// Update search positions
prev_pos = current_pos + 1;
}
// Since there is no ; at the end, we print the last number manually
std::cout << test.substr(prev_pos) << "\n\n";
}
// Solution 2. All in one statement. Just to show to you what can be done with C++
{
std::copy(std::sregex_token_iterator(test.begin(), test.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout, "\n"));
}
return 0;
}

Detecting if input string has a space

I wrote this code to detect if an input string has a space or not. Please tell what is wrong in this approach.
#include <iostream>
#include <string>
using namespace std;
int main(){
string inp;
getline(cin, inp);
for (int i = 0; i < inp.length(); i++) {
string z = to_string(inp[i]);
if (z == " ") {
cout << "space";
}
else {
i++;
}
}
}
If i enter a string with spaces, it doesn't print "space".
Since inp is an std::string, inp[i] will be a char. Since std::to_string only has overloads for arithmetic, non-char values, calling it on a char is akin to calling it on the integer representation of said char. (If you log z, you'll likely find a number printed.)
Instead, directly compare inp[i] to a space. else { i++; } is also unnecessary – you may be jumping over spaces.
for (int i = 0; i < inp.length(); i++) {
if (inp[i] == ' ') { // note single quotes for char
cout << "space";
}
}
#TrebledJ's answer explains why your code is broken and how to fix it.
Another way to handle this situation is to use std::string::find() instead:
#include <iostream>
#include <string>
int main(){
std::string inp;
std::getline(std::cin, inp);
if (inp.find(' ') != std::string::npos) {
std::cout << "space";
}
}
Alternatively, your original code tries to output "space" for each space character found. You could use find() in a loop:
#include <iostream>
#include <string>
int main(){
std::string inp;
std::getline(std::cin, inp);
std::string::size_type idx = inp.find(' ');
while (idx != std::string::npos) {
std::cout << "space at " << idx << std::endl;
idx = inp.find(' ', idx+1);
}
}

How to erase non-alphabet characters from a string without going out of range

I am trying to this function to return without numbers, spaces, or other characters and I am supposed to use the .erase function. I understand that my loop keeps going out of range, but I have no clue how to fix it and I've been stuck on this for a while. If the user types "dogs are a lot of fun" and I need the function to return and output "dogsarealotoffun" Thanks for the help.
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
//function to output string without spaces, numbers, or punctuations
string alphabetOnly (string input){
int size;
int i= 0;
size = (int)input.size();
while (input[i] < size){
if (isalpha(input[i])){
i++;
}
else
input.erase(input[i]);
}
return input;
}
int main() {
string input;
cout << "Enter a string to test: ";
getline(cin, input);
cout << "alphabetOnly: " << alphabetOnly(input) << endl;
}
EDITED: I was too hasty in my previous answer (as I am learning I need to speak from tested code rather than off the top of my head) and needed to debug. The problem is in the else case you need to erase the char, NOT increment i because the length of the string just changed, and also since the length of the string changed you need to reset size to be the new length. Sorry for the hasty answer earlier, I was speaking without actually using the compiled code.
#include <iostream>
#include <cctype>
#include <string>
//function to output string without spaces, numbers, or punctuations
std::string alphabetOnly (std::string input){
int size;
int i= 0;
size = (int)input.size();
while (i < size){
if (isalpha(input[i])){
i++;
}
else{
input.erase(i,1);
//do not increment i here since the index changed becauase of erase
size = (int)input.size();
}
}
return input;
}
int main() {
std::string input;
std::cout << "Enter a string to test: ";
std::getline(std::cin, input);
std::cout << input;
std::cout << "alphabetOnly: " << alphabetOnly(input) << std::endl;
return 0;
}
something like this:
#include <iostream>
#include <string>
#include <algorithm>
//function to output string without spaces, numbers, or punctuations
std::string alphabetOnly (std::string input)
{
auto not_alpha = [](char c) { return !std::isalpha(c); };
input.erase(std::remove_if(begin(input),
end(input),
not_alpha),
std::end(input));
return input;
}
int main() {
std::string input;
std::cout << "Enter a string to test: ";
getline(std::cin, input);
std::cout << "alphabetOnly: " << alphabetOnly(input) << std::endl;
}
http://coliru.stacked-crooked.com/a/340465d41ecd8c8e
There's quite a few things wrong with your code, but to start with here's your main error corrected.
#include <iostream>
#include <cctype>
#include <cstring>
using namespace std;
//function to output string without spaces, numbers, or punctuations
string alphabetOnly (string input){
int size;
int i= 0;
size = (int)input.size();
while (i < size){
if(isalpha(input[i]))
{
i++;
}
else
input.erase(input.begin( ) + i );
}
return input;
}
int main() {
string input;
cout << "Enter a string to test: ";
getline(cin, input);
cout << "alphabetOnly: " << alphabetOnly(input) << endl;
}
But this is awfully inefficient because you swhift all the remaining unchecked characters each time you delete.
You should use something like
input.erase( remove_if( input.begin(), input.end(), not( isalpha ) ), input.end( ));
This is known as the remove-erase idiom, whihc you can lookup anywhere.

Need Help Debugging my Code That Reverses the Words in a String

I need some help debugging my code. This code is intended to reverse the words in a string that is in the form of a sentence [assuming that the string does not have a "." at the end]. For some reason what I'm getting as an output is the indented output plus an extra space after the first word as well as the indented output minus the first word. I am a beginner at coding; so if possible, I would appreciate more simple to understand solutions, or a solution that uses a loop, strings, and arrays.
Sample Input:
My name is Edward
Intended Output:
Edward is name My
Output Received:
Edward is name
Here is my code so far:
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main() {
string s, n, a;
getline(cin, s);
for (int i = s.length(); i >= 0; i--){
if (s[i] != 32 ) {
n += s[i];
}
else {
for (int j = n.length() -1; j >= 0; j--){
a += n[j];
}
cout << a << ' ';
n.clear();
a.clear();
}
}
cin.ignore();
getchar();
return 0;
}
Also, I just noticed that there is also an extra space at the end. If there is a way to maybe cancel outputting the last space; please tell me.
Thanks for reading, I appreciate your help.
As mentioned in my comment, you're reversing the whole string by characters, but you need to split up for words and reverse:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
string s, n;
getline(cin, s);
std::istringstream iss(s);
std::vector<string> words;
while(iss >> n) {
words.push_back(n);
}
std::reverse(words.begin(),words.end());
for(auto word : words) {
std::cout << word << ' ';
}
getchar();
return 0;
}
Live Demo
So this is really just an additional step of abstraction from πάντα ῥεῖ's excellent answer. You can use istream_iterator and ostream_iterator to further simplify your code.
The entire code to answer your question can be boiled down to:
const vector<string> words{ istream_iterator<string>(cin), istream_iterator<string>() };
copy(crbegin(words), crend(words), ostream_iterator<string>(cout, " "));
Live Example
Edit: Thanks for the help from the comments and answers, I fixed the problem with the extra space and added something at the end that outputs the final word. It's not perfect, but it works. :)
#include <iostream>
#include <string>
using namespace std;
int main() {
string s, n;
getline(cin, s);
for (int i = s.length() -1; i >= 0; i--){
if (s[i] != 32) {
n += s[i];
}
else {
for (int j = n.length() -1; j >= 0; j--){
cout << n[j];
}
cout << ' ';
n.clear();
}
}
for (int k = n.length() -1 ; k >= 0; k--)
cout << n[k];
cin.get();
return 0;
}
you can use strrev(); function instead all of your for block.

array size and split of string

Ok guy i had to make a program to split elements of a string. And after that print those words.
there are some problems i am facing:
1) the array prints more than the size of the words in string i want that it should end printing as soon as last word is printed. i tried to prevent that but it always gives runtime error when i try to break at the last word.
2)is there any other efficient way to split and print ???
#include <sstream>
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include <string>
using namespace std;
int main()
{
std::string line;
std::getline(cin, line);
string arr[1000];
int i = 0;
int l=line.length();
stringstream ssin(line);
while (ssin.good() && i < l)
{
ssin >> arr[i];
++i;
}
int size = sizeof(arr) / sizeof(arr[0]);
for(i = 0; i <size; i++){
cout << arr[i] << endl;
}
return 0;
}
int size = sizeof(arr) / sizeof(arr[0]);
That is a compile time value, and it's always going to be the number of elements in your array (1000). It has no idea how many strings you assigned to in your loop. You stored the number of successfully read strings (plus 1) in the i variable, so you could do this instead:
int size = i - 1;
But if it were up to me, I would just use a growable structure, like vector (#include <vector>)
std::vector<std::string> arr;
std::string temp;
while (ssin >> temp)
{
arr.push_back(temp);
}
for (auto const & str : arr)
{
std::cout << str << std::endl;
}
/* If you're stuck in the past (can't use C++11)
for (std::vector<std::string>::iterator = arr.begin(); i != arr.end(); ++i)
{
std::cout << *i << std::endl;
}
*/
For general purpose character based splitting, I would much prefer boost::split (I know you can't use it, but for future reference)
std::vector<std::string> arr;
boost::split(arr, line, boost::is_any_of(".,;!? "));
Read up on the function strtok. It is old school but very easy to use.
1) there are a couple of changes you should make to your program:
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
std::string line("hello string world\n");
string arr[1000];
int i = 0;
stringstream ssin(line);
while (ssin.good() && i < 1000)
{
ssin >> arr[i++];
}
int size = i-1;
for(i = 0; i < size; i++){
cout << i << ": " << arr[i] << endl;
}
return 0;
}
namely, you don't want to print sizeof(arr)/sizeof(arr[0]) (i.e. 1000) elements. There is no point in the condition i < l
2) stringstream is fine if you just want to separate the single strings; if more is needed, use boost/tokenizer for splitting strings. It's modern c++, once you try it you'll never come back!
this is the best method i think no worry now
#include <sstream>
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include <cstring>
#include <string>
using namespace std;
int main ()
{
std::string str;
std::getline(cin, str);
string arr[100];
int l=0,i;
char * cstr = new char [str.length()+1];
std::strcpy (cstr, str.c_str());
// cstr now contains a c-string copy of str
char * p = std::strtok (cstr,".,;!? ");
while (p!=0)
{
//std::cout << p << '\n';
arr[l++]=p;
p = strtok(NULL,".,;!? ");
}
for(i = 0; i <l; i++)
{
cout << arr[i] << endl;
}
delete[] cstr;
return 0;
}