stringstream in cpp is continual parsing possible - c++

I've got a vector of strings wherein if the 1st character is "1" then I need to push the integer (represented as a string) into a vector else I just need to print the 1st char.
While using stringstream the following is the code ive written.
vector<string> arr = {"1 23", "2", "1 45", "3", "4"};
vector<int> v;
for(string x : arr){
stringstream ss(x);
string word;
string arr[2];
int i =0 ;
while(ss >> word){
arr[i++] = word;
}
i = 0;
if(arr[0] == "1")
v.push_back(atoi(arr[1]));
else
cout << arr[0] << endl;
Instead of using an array arr, is there a way to take the next word from stringstream once the first word is "1"? Because when I tried the stringstream began all over again from start.

The code uses std::stringstream, but it doesn't take any advantage from this object, like extracting directly an int.
std::vector<std::string> arr = {"1 23", "2", "1 45", "3", "4"};
std::vector<int> v;
for ( auto const& word : arr )
{
std::stringstream ss{ word }; // Initialize with a string,
int first;
if ( ss >> first )
{ // ^^^^^^^^^^^ but extract an int...
if ( first == 1 )
{
int second;
if ( ss >> second ) // and another.
v.push_back(second);
}
else
std::cout << first << '\n';
} // Error handling is left to the reader.
}

Assuming the strings are always well-formed and in the format you describe, and the numbers in the strings are always valid integers, you could so something like this instead:
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
using namespace std;
int main() {
const vector<string> arr = {"1 23", "2", "1 45", "3", "4"};
vector<int> v;
for (const string& s : arr) {
if (s.size() > 2 && s[0] == '1' && s[1] == ' ') {
v.push_back(atoi(s.c_str() + 2));
} else {
cout << s << "\n";
}
}
for (const int i: v) {
cout << i << "\n";
}
}
For strings in the array that don't start with a 1 and a space that you said you're just supposed to print, I just printed out the whole string instead of its first character.
If you're not sure about your strings in the array, you'll need to check for errors first. Also, see How can I convert a std::string to int? for alternatives to atoi().

Related

C++ - Parsing number from std::string [duplicate]

This question already has answers here:
C++ Extract number from the middle of a string
(8 answers)
Closed 5 years ago.
I need to iterate through a shopping list which I have put into a vector and further separate each line by the quantity and item name. How can I get a pair with the number as the first item and the item name as the second?
Example:
vector<string> shopping_list = {"3 Apples", "5 Mandarin Oranges", "24 Eggs", "152 Chickens"}
I'm not sure how big the number will be so I can't use a constant index.
Ideally I would like a vector of pairs.
You can write a function to split quantity and item like following:
#include <sstream>
auto split( const std::string &p ) {
int num;
std::string item;
std::istringstream ss ( p);
ss >>num ; // assuming format is integer followed by space then item
getline(ss, item); // remaining string
return make_pair(num,item) ;
}
Then use std::transform to get vector of pairs :
std::transform( shopping_list.cbegin(),
shopping_list.cend(),
std::back_inserter(items),
split );
See Here
I suggest you the following solution without stringstream just as alternative solution
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> shopping_list = { "3 Apples", "5 Mandarin Oranges", "24 Eggs", "152 Chickens" };
vector< pair<int, string> > pairs_list;
for (string s : shopping_list)
{
int num;
string name;
int space_pos = s.find_first_of(" ");
if (space_pos == std::string::npos)
continue; // format is broken : no spaces
try{
name = s.substr(space_pos + 1);
num = std::stoi(s.substr(0, space_pos));
}
catch (...)
{
continue; // format is broken : any problem
}
pairs_list.push_back(make_pair(num, name));
}
for (auto p : pairs_list)
{
cout << p.first << " : " << p.second << endl;
}
return 0;
}
You can use std::stringstream as follows.
vector< pair<int,string> > myList;
for(int i=0;i<shopping_list.size();i++) {
int num;
string item;
std::stringstream ss;
ss<<shopping_list[i];
ss>>num;
ss>>item;
myList.push_back(make_pair(num,item));
...
}
num is your required number.

Reverse word order in sentence

I'm having difficulty creating a function that reverse the order of the sentence around. I've read many functions on how to recursively reverse the letters around and I have successfully done so, but I do not want to reverse the letters in the words. I want to reverse the placement of the words in the sentence.
Example would be:
This is a sentence.
sentence. a is This
This is my code so far. How do I go from reversing order of letters of the entire sentence to placement order of words in a sentence?
The output of the current code would provide: !dlroW olleH
void reverse(const std::string str)
{
int length = str.size();
if(length > 0)
{
reverse(str.substr(0,length-1));
std::cout << str[0];
}
}
Edit: Additional question. If this was a char array would the logic be different?
Simplify your logic by using a std::istringstream and a helper function. The program below works for me.
#include <sstream>
#include <iostream>
void reverse(std::istringstream& stream)
{
std::string word;
if ( stream >> word )
{
reverse(stream);
std::cout << word << " ";
}
}
void reverse(const std::string str)
{
std::istringstream stream(str);
reverse(stream);
std::cout << std::endl;
}
int main(int argc, char** argv)
{
reverse(argv[1]);
return 0;
}
// Pass string which comes after space
// reverse("This is a sentence.")
// reverse("is a sentence.")
// reverse("a sentence.")
// reverse("sentence.")
// will not find space
// start print only word in that function
void reverse(const std::string str)
{
int pos = str.find_first_of(" ");
if (pos == string::npos) // exit condition
{
string str1 = str.substr(0, pos);
cout << str1.c_str() << " " ;
return;
}
reverse(str.substr(pos+1));
cout << str.substr(0, pos).c_str() << " ";
}
Simple to understand:
void reverse(const std::string str)
{
int pos = str.find_first_of(" ");
if (pos != string::npos) // exit condition
{
reverse(str.substr(pos + 1));
}
cout << str.substr(0, pos).c_str() << " ";
}
std::vector<std::string> splitString(const std::string &s, char delim) {
std::stringstream ss(s);
std::string item;
std::vector<std::string> tokens;
while (getline(ss, item, delim)) {
tokens.push_back(item);
}
return tokens;
}
void reverseString(const std::string& string) {
std::vector<std::string> words = splitString(string, ' ');
auto end = words.rend();
for (auto it = words.rbegin(); it <= end; it++) {
std::cout << *it << std::endl;
}
}
reverseString("This is a sentence.");
You can split input and print them in inverse order
Or if you want to use recursive structure just move the cout after calling a function like this:
void reverse(const std::string str)
{
std::stringstream ss(str);
std::string firstWord, rest;
if(ss >> firstWord)
{
getline(ss , rest);
reverse(rest);
std::cout << firstWord << " ";
}
}
I am not a C++ programmer, but I would create another array (tempWord[ ]) to store individual word.
Scan each word and store them into tempWord array. In your case, the words are separated by space, so:
a.get the index of the next space,
b substring to the index of the next space and
c. you should get {"This", "is", "a", "sentence."}
Add them up again reversely:
a. loop index i from "tempWord.length -1" to "0"
b. new String = tempWord[i]+" ";
print out result.

Scan string and store numbers and operations in different vectors C++

Suppose I have a string exp in the following format:
123+456*789-1011+1213
I want to store all the numbers in vector numbers, and all the operations in vector op.
vector<long long>numbers // {123, 456, 789, 1011, 1213}
vector<char>op // {+, *, -, +}
for (int i = 0; i < exp.size(); i++){
if (exp[i]=="+" || exp[i]=="-" || exp[i]=="*"){
op.push_back(exp[i]);
}else{
...
}
}
How do I store the numbers, and convert them from char to long long?
You will need to parse the input expression to extract the numbers and operator.
There are many ways by which this can be done, however following is my approach.
Traverse through all the character and push the values in Operator vector which is not a digit and replace it with space.
Now extract the numbers from the expression and convert it to numbers and push the values in Number vector.
To know how to split a string you can check the following links:
Split a string - Stack overflow
Split a string - cplusplus.com
Use stol or strtol or string stream to convert string to long value.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main()
{
std::string exp = "123+456*789-1011+1213";
std::vector<long> vecNums;
std::vector<char> vecOper;
for (decltype(exp.size()) i = 0; i < exp.size(); ++i) {
if (!isdigit(exp[i])) {
vecOper.push_back(exp[i]);
exp[i] = ' ';
}
}
std::istringstream iss(exp);
while (iss) {
std::string substr;
long num;
std::getline(iss, substr, ' ');
if (substr.size() != 0) {
// Using strtol function
// num = strtol(substr.c_str(), NULL, 10);
// Using stol function
num = stol(substr);
vecNums.push_back(num);
}
//
// Or use string stream to convert string to long
//
//long num;
//iss >> num;
//vecNums.push_back(num);
}
std::cout << "Numbers: " << std::endl;
for (auto &i : vecNums) {
std::cout << i << " ";
}
std::cout << "\nOperators: " << std::endl;
for (auto &i : vecOper)
std::cout << i << " ";
return 0;
}
If you're going to use iostreams:
void parse_string(const string& s) {
using num_t = long long;
using op_t = char;
istringstream sstr(s);
vector<num_t> numbers;
vector<op_t> ops;
(void)sstr.peek(); //set eofbit if s.empty()
while (!sstr.eof() && !sstr.fail()) {
num_t num;
sstr >> num;
if (!sstr.fail()) {
numbers.push_back(num);
if (!sstr.eof()) {
op_t op;
sstr >> op;
if (!sstr.fail()) {
ops.push_back(op);
}
}
}
}
//assert(ops.size() + 1 == numbers.size());
//copy(begin(numbers), end(numbers), ostream_iterator<num_t>(cout, " "));
//copy(begin(ops), end(ops), ostream_iterator<op_t>(cout, " "));
}
Error checking code as been removed (validate operators are correct, exceptions).

How to user input the array elements in c++ in one line

I am new to c++ , Basically I belong to PHP . So I am trying to write a program just for practice, to sort an array . I have successfully created the program with static array value that is
// sort algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
bool myfunction (int i,int j) { return (i<j); }
struct myclass { bool operator() (int i,int j) { return (i<j);} } myobject;
int main () {
int myints[] = {55,82,12,450,69,80,93,33};
std::vector<int> myvector (myints, myints+8);
// using default comparison (operator <):
std::sort (myvector.begin(), myvector.begin()+4);
// using function as comp
std::sort (myvector.begin()+4, myvector.end(), myfunction);
// using object as comp
std::sort (myvector.begin(), myvector.end(), myobject);
// print out content:
std::cout << "myvector contains:";
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
its output is ok . But I want that the elements should input from user with space separated or , separated . So i have tried this
int main () {
char values;
std::cout << "Enter , seperated values :";
std::cin >> values;
int myints[] = {values};
/* other function same */
}
it is not throwing an error while compiling. But op is not as required . It is
Enter , seperated values :20,56,67,45
myvector contains: 0 0 0 0 50
3276800 4196784 4196784
------------------ (program exited with code: 0) Press return to continue
You can use this simple example:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
using namespace std;
int main()
{
stringstream ss;
string str;
getline(cin, str);
replace( str.begin(), str.end(), ',', ' ');
ss << str;
int x = 0;
while (ss >> x)
{
cout << x << endl;
}
}
Live demo
or, if you want to have it more generic and nicely enclosed within a function returning std::vector:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
using namespace std;
template <typename T>
vector<T> getSeparatedValuesFromUser(char separator = ',')
{
stringstream ss;
string str;
getline(cin, str);
replace(str.begin(), str.end(), separator, ' ');
ss << str;
T value{0};
vector<T> values;
while (ss >> value)
{
values.push_back(value);
}
return values;
}
int main()
{
cout << "Enter , seperated values: ";
auto values = getSeparatedValuesFromUser<int>();
//display values
cout << "Read values: " << endl;
for (auto v : values)
{
cout << v << endl;
}
}
Live demo
Read in all the values into one string, then use a tokenizer to separate out the individual values.
How do I tokenize a string in C++?
The above answers are very good for an arbitrary number of inputs, but if you allready know how many numbers will be put, you could do it like:
int[5] intList;
std::cin >> intList[0] >> intList[1] >> intList[2] >> intList[3] >> intList[4]
But please note that this method does not do any check if the numbers are put properly, so if there are for example letters or special characters in the input, you might get unexpected behavior.
Let's see what you wrote:
int main () {
char values;
std::cout << "Enter , seperated values :";
std::cin >> values; // read a single character
int myints[] = {values}; // create a static array of size 1 containing the single character converted to an int
/* other function same */
}
what you need is:
#include <sstream>
#include <string>
...
int main () {
std::cout << "Enter space seperated values :";
std::vector<int> myvector;
std::string line;
std::getline(std::cin, line); // read characters until end of line into the string
std::istringstream iss(line); // creates an input string stream to parse the line
while(iss >> value) // so long as values can be parsed
myvector.push_back(value); // append the parsed value to the vector
/* other function same */
}
If you want comma separated input you'll need to parse the comma as a single character in addition to the integer values.
What you are doing
int main () {
char values; //Declare space for one character
std::cout << "Enter , seperated values :"; //Ask user to enter a value
std::cin >> values; //Read into values (one value only)
int myints[] = {values}; // assign the first element to the ASCII code of whatever user typed.
/* other function same */
}
In the language char works as an 8-bit integer. Through function overloading, different behavior can be implemented. Read about static polymorphism for more details how it works.
What you need to do
std::vector<int> values;
char ch_in;
std::string temp;
while(cin.get(ch_in)) {
switch(ch_in) {
case ',':
case ' ': //Fall through
values.push_back(atoi(temp.c_str()); //include cstdlib for atoi
temp.clear();
break;
default:
temp+=ch_in;
}
}
You should put this in a separate function. With this skeleton, you can implement a more fancy syntax by adding more cases, but then you need something else than a std::vector<int> to put things into. You can (should?) also add error checking in the default case:
default:
if( (ch_in>='0' && ch_in<='9')
|| (temp.size()==0 && ch_in=='-') ) {
temp+=ch_in;
}
else {
cerr<<ch_in<<" is an illegal character here."
temp.clear();
}
#include <iostream>
#include <string>
#include <sstream>
#include <string.h>
using namespace std;
// THIS CODE IS TO GIVE ARRAY IN ONE LINE AND OF DESIRED LENGHT ALSO WITH NEGATIVE NUMBERS
// You can also do it by using ASCII but we Are using library name
// <sstream> to convert string charters to numbers
//O(n) time complexity
int main()
{
/*
// INPUT
// 7 array length
// 34-56-789 // without space b/w them */
int N;
cout << "Enter the size of the array " << endl;
cin >> N;
cout << "INPUT Without giving space b/w " << endl;
string strx;
cin >> strx;
int X[N]; // array to store num
int p = 0;
// NOTE USE HERE STRX.LENGHT() becouse we have to go through the whole string
for (int i = 0; i < strx.length(); i++)
{ // we have declare tempx to store a particular character
// one time
string tempx;
tempx = strx[i];
stringstream strtointx(tempx);
// this is the syntax to convert char to int using <sstream>
if (strx[i] == '-')
{
/*
The tricky point is when you give string as 1-23
here - and 2 are the separte characters so we are not
getting -2 as number but - and 2 so what we do is
we chek for '-' sign as the character next to it
will be treated as negative number
*/
tempx = strx[i + 1];
// by assigning strx[i+1] to tempx so that we can getting the which should be treated as negative number
stringstream strtointx(tempx);
// still it is a charter type now again using library
// convert it to int type
strtointx >> X[p];
X[p] = -X[p];
// now make that number to negative ones as we want it to be negative
i++;
// inside this if i++ will help you to skip the next charcter of string
// so you can get desired output
}
// now for all the positive ones to int type
else{ strtointx >> X[p]; }
p++; // finally increment p by 1 outside if and else block
}
// loop ends now get your desired output
cout<<"OUTPUT "<<endl;
for (int i = 0; i < N; i++)
{
cout << X[i] << " ";
}
cout<<endl;
cout<<"CODE BY MUKUL RANA NIT SGR Bch(2020)";
return 0;
}
// OUTPUT
/*
Enter the size of the array
7
INPUT Without giving space b/w
34-56-789
OUTPUT
3 4 -5 6 -7 8 9
CODE BY MUKUL RANA NIT SGR Bch(2020)
PS C:\Users\user\Desktop\study c++>
*/
// CAUTION :
/*
1) do not give input with spaces
**** if you do then first you have to change /chek the code for spaces indexes also ***
2)do not give charates as 56-89##13 as you want here only numbers
3) this only for integer if you want to float or double you have to do some changes here
because charters index and length would be difeerent in string.
*/

C++ how to get ONLY integers from complex string

I have few strings, each one contains one word and several integer numbers (One string is whole line):
Adam 2 5 1 5 3 4
John 1 4 2 5 22 7
Kate 7 3 4 2 1 15
Bill 2222 2 22 11 111
As you can see, each word/number is separated with space. Now, I want to load these data into a map, where word (name) would be the key and the value would be vector of the numbers in line. I already have key values in separated temporary stl container, so the task is to load only the integer numbers from each line to 2D vector and then merge these two into map.
The question is, is there any C++ function, which would avoid words and white spaces and get only integers from a string, or I have to search strings char-by-char like
here ?
I found only partial solution, which is not able to get more than one digit number:
vector<int> out;
for (int i = 0; i < line.length(); i++) {
if (isdigit(line.at(i))) {
stringstream const_char;
int intValue;
const_char << line.at(i);
const_char >> intValue;
out.push_back(intValue);
}
}
If every line has the format "word number number number ...", use a stringstream and skip the word by reading it.
If the current line is in line:
vector<int> out;
istringstream in(line);
string word;
in >> word;
int x = 0;
while (in >> x)
{
out.push_back(x);
}
split the string on spaces since that seems to be your delimiter. Then check that each substring contains an int with strol.
Then use stoi to convert the integer substrings to int.
If no stoi conversion can be performed (the string does not contain a number), an invalid_argument exception is thrown, so don't try to convert the name substring.
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <cstdlib>
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
inline bool isInteger(const std::string & s)
{
if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ;
char * p ;
strtol(s.c_str(), &p, 10) ;
return (*p == 0) ;
}
int main()
{
std::cout << "Hello World" << std::endl;
std::string example="Adam 2 5 1 5 3 4";
std::vector<std::string> subStrings;
subStrings = split(example, ' ');
std::string sItem;
for(std::vector<std::string>::iterator it = subStrings.begin(); it != subStrings.end(); ++it) {
sItem = *it;
if( isInteger(sItem) ){
int nItem = std::stoi (sItem);
std::cout << nItem << '\n';
}
}
return 0;
}
use find() and substr() of string Class to find the name if it is always at the beginning of the string.
std::string s = "Adam 2 5 1 5 3 4";
std::string delimiter = " ";
s.substr(0, s.find(delimiter)); //To get the name
s.erase(0, s.find(delimiter)); //To delete the name
//Repeat the mechanism with a for or a while for the numbers
I do not test this solution but I use something similar with always the label in first place.
If the name could be anywhere, I do not see how test it without check for every character.
Here is a program that demonstrates an approach to the task that can be used.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <iterator>
int main()
{
std::string s( "Adam 2 5 1 5 3 4" );
std::map<std::string, std::vector<int>> m;
std::string key;
std::istringstream is( s );
if ( is >> key )
{
m[key] = std::vector<int>( std::istream_iterator<int>( is ),
std::istream_iterator<int>() );
}
for ( const auto &p : m )
{
std::cout << p.first << ": ";
for ( int x : p.second ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
Adam: 2 5 1 5 3 4
Assuming that the name comes first, here is a function that will read the string and add to the map.
#include <map>
#include <vector>
#include <sstream>
#include <string>
#include <algorithm>
using namespace std;
typedef std::map<std::string, std::vector<int> > StringMap;
void AddToMap(StringMap& sMap, const std::string& line)
{
// copy string to stream and get the name
istringstream strm(line);
string name;
strm >> name;
// iterate through the ints and populate the vector
StringMap::iterator it = sMap.insert(make_pair(name, std::vector<int>())).first;
int num;
while (strm >> num)
it->second.push_back(num);
}
The function above adds a new entry to the map with the first read, and on subsequent reads, populates the vector.
Note that the map::insert function returns a std::pair, where the first of that pair is the iterator to the map entry that was created. So we just get the iterator, and from there, push_back the entries.
Here is a test program:
int main()
{
vector<std::string> data = { "Adam 2 5 1 5 3 4", "John 1 4 2 5 22 7",
"Kate 7 3 4 2 1 15", "Bill 2222 2 22 11 111" };
StringMap vectMap;
// Add results to map
for_each(data.begin(), data.end(),
[&](const std::string& s){AddToMap(vectMap, s); });
// Output the results
for_each(vectMap.begin(), vectMap.end(),
[](const StringMap::value_type& vt)
{cout << vt.first << " "; copy(vt.second.begin(), vt.second.end(),
ostream_iterator<int>(cout, " ")); cout << "\n"; });
}
Live example: http://ideone.com/8UlnX2