I've started working on hackerrank/hackerearth like sites. There i've found one problem fetching input. Its easy in Java.
Consider a very simple problem of reading input and displaying it :
Flow is like :
read A
repeat A times
read X1,N1,X2,N2 ; where Xi is any string, Ni is any integer.
display X1+X2, N1+N2
i don't know how to read X1,N1,X2,N2 where X1 and X2 are strings, i've also tried but problem is that when i read first string it reads entire line for eg when i read string it supposed to be X1 but it is X1,N1,X2,N2. code that i used is
scanf("%s,%d,%s,%d", x1, &n1, x2, &n2)
thanks in advance and sorry for my bad english.
Update#1:
example lines :
3
some,123,thing,456
something,579
a,1,b,2
ab,3
hello,100,world,100
helloworld,200
I think you are looking for something like this:
int number_of_inputs;
std::cin >> number_of_inputs;
for (int iteration = 0; iteration < number_of_inputs; ++iteration){
int integer1, integer2;
string string1, string2, stupid_comma;
std::cin >> string1 >> stupid_comma >> integer1 >> stupid_comma >> string2 >> stupid_comma >> integer2;
std::cout << string1 << " + " << string2 << " = " << integer1+integer2 << std::endl;
}
edit2: After op provides input, my code is not correct. Check this answer: Parsing a comma-delimited std::string
edit3: alternative split method op requires:
std::vector<std::string> split(const std::string &text, char sep, int num)
{
std::vector<std::string> tokens;
std::size_t start = 0, end = 0;
int elements = 0;
while ((end = text.find(sep, start)) != std::string::npos) {
if ( elements == num) break;
tokens.push_back(text.substr(start, end - start));
start = end + 1;
elements++;
}
tokens.push_back(text.substr(start));
return tokens;
}
edit4: new code using split function:
int number_of_inputs;
std::cin >> number_of_inputs;
for (int iteration = 0; iteration < number_of_inputs; ++iteration){
std:string line;
cin >> line;
int integer1, integer2;
string string1, string2, stupid_comma;
std::vector<std::string> my_line = split(line, ',', 4);
string1 = my_line[0];
string2 = my_line[2];
integer1 = stoll(my_line[1], nullptr, 10);
integer2 = stoll(my_line[3], nullptr, 10);
std::cout << string1 << " + " << string2 << " = " << integer1+integer2 << std::endl;
}
Here is a solution using std::regex, even though it is longer than the accepted answer, I find it much clearer and more flexible.
#include <iostream>
#include <string>
#include <regex>
using namespace std;
struct MyPair {
string x; int n;
MyPair() {}
MyPair( const string& x, int n )
: x(x), n(n) {}
};
void parse_line( const string& str, MyPair& p1, MyPair& p2 ) {
typedef regex_iterator<string::const_iterator> re_iterator;
typedef re_iterator::value_type re_iterated;
regex re("(\\w+),(\\d+),(\\w+),(\\d+)");
re_iterator rit( str.begin(), str.end(), re );
re_iterator rend;
if ( rit != rend ) {
p1 = MyPair( (*rit)[1], stoi((*rit)[2]) );
p2 = MyPair( (*rit)[3], stoi((*rit)[4]) );
}
}
int main() {
int A = 0;
while ( A <= 0 ) {
cin >> A;
}
string line;
MyPair p1, p2;
for ( int i = 0; i < A; i++ ) {
cin >> line;
parse_line( line, p1, p2 );
cout << (p1.x + p2.x) << " " << (p1.n + p2.n) << endl;
}
}
Note that it uses features from C++11, so in order to compile it using clang++ (for instance), you should do:
clang++ -std=c++11 file.cpp -o file
Related
I need to sum 100, 200, 300 in a.txt
a.txt
2323|A|5|0|2|100
2424|B|6|1|3|200
2525|C|7|2|4|300
so I opened this file, and read line by line using getline(), and tokenized.
main.cpp
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)) {
for (int i = 0; i < tokens.size(); i++) {
std::cout << tokens[i] << std::endl;
tokens.pop_back();
}
}
As expected, that code printed singly of all things.
so I thought using token index to sum values. but my code have error.
"vector subscript out of range" or no compile.
first try
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)) {
for (int i = 0; i < tokens.size(); i++) {
std::cout << tokens[i] << std::endl;
tokens.pop_back();
std::cout << tokens[5] << std::endl;
std::cout << tokens[11] << std::endl;
std::cout << tokens[17] << std::endl;
int a = 0;
int b = 0;
int c = 0;
int sum = 0;
a = stoi(tokens[5]);
b = stoi(tokens[11]);
c = stoi(tokens[17]);
sum = (a + b + c);
std::cout << sum << std::endl;
}
}
second try
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each)) {
if(tokens.size() > 4) {
for (int k = 0; k < ((tokens.size() - 5) / 6) + 1; k++) {
int sum = 0;
int change = 0;
int j = 0;
j = 6 * k + 5;
change = stoi(tokens[j]);
sum += change;
std::cout << sum << std::endl;
tokens.pop_back();
}
}
}
what should I do sum value? and I'm wondering that tokens.size()`s meaning except meaning "size" because second for statement always get an error if not exactly correcting i < tokens.size()
You are modifying the tokens vector while you are looping through it. Don't do that. You are affecting its size(), which accounts for why you are able to go out of bounds.
You say that you need to sum only the last token of each line. But that is not what your code is trying to do. There is no need for an inner for loop at all. Simply split each line into a local tokens vector and then use tokens.back() to get the last token, eg:
std::string line;
int sum = 0;
while (std::getline(inFile, line))
{
std::istringstream iss(line);
std::vector<std::string> tokens;
std::string token;
while (std::getline(iss, token, '|')) {
tokens.push_back(token);
}
// use tokens as needed...
token = tokens.back();
sum += std::stoi(token);
}
std::cout << sum << std::endl;
Live Demo
I would like to structure my code slightly differently.
Rather than try and do everything in the main function split your code up so that you read each line and validate it is correct:
#include <iostream>
#include <string>
// A structure representing the data we want to parse.
struct DataLine
{
int v1;
char c;
int v2;
int v3;
int v4;
int v5;
// An input operator that will read one line of data.
// If the data is valid will update the variable we are reading into.
friend std::istream& operator>>(std::istream& str, DataLine& data)
{
DataLine tmp;
char s[5];
std::string extra;
if ( str >> tmp.v1 >> s[0] && s[0] == '|'
&& str >> tmp.c >> s[1] && s[1] == '|'
&& str >> tmp.v2 >> s[2] && s[2] == '|'
&& str >> tmp.v3 >> s[3] && s[3] == '|'
&& str >> tmp.v4 >> s[4] && s[4] == '|'
&& str >> tmp.v5
&& std::getline(str, extra) && extra.empty())
{
// all the data was read and the line was valid.
// update the correct variable.
swap(tmp, data);
}
else {
// there was an issue.
// set the stream to bad so that reading will stop.
str.setstate(std::ios::badbit);
}
return str;
}
// Standard swap method.
friend void swap(DataLine& lhs, DataLine& rhs) noexcept
{
using std::swap;
swap(lhs.v1, rhs.v1);
swap(lhs.c , rhs.c );
swap(lhs.v2, rhs.v2);
swap(lhs.v3, rhs.v3);
swap(lhs.v4, rhs.v4);
swap(lhs.v5, rhs.v5);
}
};
Then the loop you use to read the data becomes really trivial to implement.
int main()
{
DataLine data;
int sum = 0;
// Now we can read the data in a simple loop.
while(std::cin >> data) {
sum += data.v5;
}
std::cout << "Sum: " << sum << "\n";
}
This question already has answers here:
How do I iterate over the words of a string?
(84 answers)
Closed 5 years ago.
I am trying to split a single string, with spaces, into three separate strings. For example, I have one string (str1). The user inputs any 3 words such as
"Hey it's me" or "It's hot out".
From there, I need to write a function that will take this string (str1) and divide it up into three different strings. So that (taking the first example) it will then say:
Hey (is the first part of the string)
it's (is the second part of the string)
me (is the third part of the string)
I'm having difficulty which manipulation I should be using to split the string at the spaces.
This is the code I have so far, which is just how the user will enter input.I am looking for the most basic way to accomplish this WITHOUT using istringstream! Using only basic string manipulation such as find(), substr().
** I am looking to create a separate function to perform the breaking up of string ** I figured out how to get the first section of input with this code:
cout << "Enter a string" << endl;
getline(cin, one);
position = str1.find(' ', position);
first_section = str1.substr(0, position);
But now I have no idea how to get the second section or the third section of the string to be divided up into their own string. I was thinking a for loop maybe?? Not sure.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str1;
cout << "Enter three words: ";
getline(cin, str1);
while(cin) {
cout << "Original string: " << str1 << endl;
cin >> str1;
}
return;
}
I'm having difficulty which manipulation I should be using to split the string at the spaces.
Use a std::istringstream from str1.
Read each of the tokens from the std::istringstream.
// No need to use a while loop unless you wish to do the same
// thing for multiple lines.
// while(cin) {
cout << "Original string: " << str1 << endl;
std::istringstream stream(str1);
std::string token1;
std::string token2;
std::string token3;
stream >> token1 >> token2 >> token3;
// Use the tokens anyway you wish
// }
If you wish to do the same thing for multiple lines of input, use:
int main() {
string str1;
cout << "Enter three words: ";
while(getline(cin, str1))
{
cout << "Original string: " << str1 << endl;
std::istringstream stream(str1);
std::string token1;
std::string token2;
std::string token3;
stream >> token1 >> token2 >> token3;
// Use the tokens anyway you wish
// Prompt the user for another line
cout << "Enter three words: ";
}
}
Perhaps the most basic solution is to use that which resides inside of your loop to read a single word. For example:
cin >> word1; // extracts the first word
cin >> word2; // extracts the second word
getline(cin, line); // extracts the rest of the line
You can use the result or return value of these expressions to check success:
#include <string>
#include <iostream>
int main(void) {
std::string word1, word2, line;
int success = std::cin >> word1 && std::cin >> word2
&& !!std::getline(std::cin, line); // double-! necessary?
if (success) { std::cout << "GOOD NEWS!" << std::endl; }
else { std::cout << "bad news :(" << std::endl; }
return 0;
}
Alternatively, in such a string I would expect two spaces. My suggestion would be to use string::find to locate the first and second spaces like so:
size_t first_position = str1.find(' ', 0);
You should probably check this against string::npos as an opportunity to handle errors. Following that:
size_t second_position = str1.find(' ', first_position + 1);
Next error handling check and after that, it should then be trivial to use string::substr to split that string into sections like so:
string first_section = str1.substr(0 , first_position)
, second_section = str1.substr(first_position , second_position)
, third_section = str1.substr(second_position, string::npos);
I have this Utility class that has a bunch of methods for string manipulation. I will show the class function for splitting strings with a delimiter. This class has private constructor so you can not create an instance of this class. All the methods are static methods.
Utility.h
#ifndef UTILITY_H
#define UTILITY_h
// Library Includes Here: vector, string etc.
class Utility {
public:
static std::vector<std::string> splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty = true );
private:
Utility();
};
Utility.cpp
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
}
Main.cpp -- Usage
#include <string>
#include <vector>
#include "Utility.h"
int main() {
std::string myString( "Hello World How Are You Today" );
std::vector<std::string> vStrings = Utility::splitString( myString, " " );
// Check Vector Of Strings
for ( unsigned n = 0; n < vStrings.size(); ++n ) {
std::cout << vStrings[n] << " ";
}
std::cout << std::endl;
// The Delimiter is also not restricted to just a single character
std::string myString2( "Hello, World, How, Are, You, Today" );
// Clear Out Vector
vStrings.clear();
vStrings = Utility::splitString( myString2, ", " ); // Delimiter = Comma & Space
// Test Vector Again
for ( unsigned n = 0; n < vStrings.size(); ++n ) {
std::cout << vStrings[n] << " ";
}
std::cout << std::endl;
return 0;
}
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).
Currently,
I have this string us,muscoy,Muscoy,CA,,34.1541667,-117.3433333.
I need to parse US and CA. I was able to parse US correctly by this:
std::string line;
std::ifstream myfile ("/Users/settingj/Documents/Country-State Parse/worldcitiespop.txt");
while( std::getline( myfile, line ) )
{
while ( myfile.good() )
{
getline (myfile,line);
//std::cout << line << std::endl;
std::cout << "Country:";
for (int i = 0; i < 2/*line.length()*/; i++)
{
std::cout << line[i];
}
}
}
But i'm having an issue parsing to CA.
Heres some code I dug up to find the amount of ',' occurrences in a string but I am having issues saying "parse this string between the 3rd and 4th ',' occurrence.
// Counts the number of ',' occurrences
size_t n = std::count(line.begin(), line.end(), ',');
std::cout << n << std::endl;
You can use boost::split function (or boost::tokenizer) for this purpose. It will split string into vector<string>.
std::string line;
std::vector<std::string> results;
boost::split(results, line, boost::is_any_of(","));
std::string state = results[3];
It's not for a class... Haha... it seems like a class question though...
I have the solution:
int count = 0;
for (int i = 0; i < line.length(); i++)
{
if (line[i] == ',')
count++;
if (count == 3){
std::cout << line[i+1];
if (line[i+1] == ',')
break;
}
}
Just had to think about it more :P
This is STL version, works pretty well for simple comma separated input files.
#include<fstream>
#include <string>
#include <iostream>
#include<vector>
#include<sstream>
std::vector<std::string> getValues(std::istream& str)
{
std::vector<std::string> result;
std::string line;
std::getline(str,line);
std::stringstream lineS(line);
std::string cell;
while(std::getline(lineS,cell,','))
result.push_back(cell);
return result;
}
int main()
{
std::ifstream f("input.txt");
std::string s;
//Create a vector or vector of strings for rows and columns
std::vector< std::vector<std::string> > v;
while(!f.eof())
v.push_back(getValues(f));
for (auto i:v)
{
for(auto j:i)
std::cout<<j<< " ";
std::cout<<std::endl;
}
}
I've an input formatted like this:
integer multi-word-string integer
I know the maximum lenght of multi-word-string, however I don't know how many words it contains. How can I read it ?
I'd read the line first and convert the first and last word to integers. Loosely:
std::string line;
std::getline(infile, line);
size_t ofs_front = line.find(' ');
size_t ofs_back = line.rfind(' ');
int front = std::strtol(line.substr(0, ofs_front).c_str(), NULL, 0);
int back = std::strtol(line.substr(ofs_back).c_str(), NULL, 0);
std::string text = line.substr(ofs_front, ofs_back - ofs_front);
You'll have to do some modifications to get rid of spaces (e.g. increment the offsets to gobble up all spaces), and you should add lots of error checking.
If you want to normalize all the interior spaces inside the text, then there's another solution using string streams:
std::vector<std::string> tokens;
{
std::istringstream iss(line);
std::string token;
while (iss >> token) tokens.push_back(token);
}
// process tokens.front() and tokens.back() for the integers, as above
std::string text = tokens[1];
for (std::size_t i = 2; i + 1 < tokens.size(); ++i) text += " " + tokens[i];
Read the first integer. Jump to back of the string and skip digits. Then read an int from this point. The part in the middle is the string. May not be 100% correct but:
char buf[256], *t = buf, *p, str[256];
fread(buf, 1, 256, file);
int s,e;
t += sscanf(buf, "%d", &s);
*p = buf + strlen(buf);
while (isdigit(*p)) p--;
sscanf(p, "%d", &e);
strncpy(str, p, p - t);
This is not as efficient as #KerrekSB's solution, but another way to do this is to extract the first integer, then loop through the rest of the string until you find the second integer.
#include <iostream>
#include <sstream>
int main()
{
std::istringstream ss( "100 4 words to discard 200" );
int first, second;
char buf[1000] = {0};
if( !( ss >> first ) ) {
std::cout << "failed to read first int\n";
return 1;
}
while( !( ss >> second ) || !ss.eof() ) {
if( ss.eof() ) {
std::cout << "failed to read second int\n";
return 1;
}
ss.clear();
if( ss.getline( buf, 1000, ' ' ).bad() ) {
std::cout << "error extracting word\n";
return 1;
}
}
std::cout << "first = " << first << "\n";
std::cout << "second = " << second << "\n";
return 0;
}