I am making a natural language calculator in C++. The user will input a line of string for calculation. The program will extract the numbers and the operation and apply it accordingly. Following is part of my code
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string inp;
float n1,n2;
string s1,s2;
cout<<"Enter your string"<<endl;
getline(cin,inp);
stringstream ss;
ss.str(inp);
ss>>s1>>n1>>s2>>n2;
}
The program will run successfully if the user enters in correct format i.e Add 2 and 3, Subtract 8 from 12.
But the problem is in two cases
If the user enters in some other format like "7 plus 6".
Even in the correct format but only one number "square root of 25".
Is there a solution which can extract the floats regardless of the position or number of floats?
Thanks
If what you want to do is literally extract the floats, you can take advantage of the fact that std::stof can additionally return where it leaves off, which you can use to determine if the entire "word" is a float (e.g. for "6c") and catch the invalid_argument for words that are definitely not floats (e.g. for "plus"):
std::vector<float> getFloats(const std::string& s) {
std::istringstream iss(s);
std::string word;
std::vector<float> result;
size_t pos = 0;
while (iss >> word) {
try {
float f = std::stof(word, &pos);
if (pos == word.size()) {
result.push_back(f);
}
}
catch (std::invalid_argument const& ) {
// no part of word is a float
continue;
}
}
return result;
}
With that, getFloats("7 plus 6") yields {7, 6} and getFloats("square root of 25") yields {25}.
Related
There is this problem on codeforces, double ended strings. I have written a code for it which works according to me for all test cases I throw at it. But, I get a wrong answer on test case 2 upon submission. The test case contains 100 inputs and after 51st input my code outputs a single value (8 in my case). It seems the 51st input somehow messes with the code and code doesn't output correct answer for the further inputs. I am not able to see what the 51st input is, as the codeforces shows only few of the input from of the beginning (49 inputs in my case). The code works absolutely fine for those inputs but fails after 51st input.
I know it's lot to ask here on stack overflow, but I am a beginner and can't figure out what's going on.
I have the added the code below with proper comments. Please someone take the efforts to look through it. Thanks in advance.
//This code reads input from 'input.txt' file and
//writes output to 'output.txt' file.
#include<bits/stdc++.h>
#include<string>
#define ll long long
#define ld long double
#define mod(x,y) (x>y ? x-y : y-x)
#define sq(x) (x*x)
using namespace std;
//This function finds all possible substrings and stores them in memo.
set<string> memo;
void recurse(string s) {
if(memo.find(s) != memo.end() or s.size() == 0) return;
recurse(s.substr(1,s.size()-1));
memo.insert(s);
recurse(s.substr(0,s.size()-1));
}
int solve(string a, string b) {
string temp;
int an = a.size(), bn = b.size();
//Obtain all possible substrings for string with less length.
if(an>bn) {
recurse(b);
temp = a;
}
else {
recurse(a);
temp = b;
}
//iterating through the memo to find the a substring
// of max length which is also the part of other string.
int MAX=0;
set<string>::iterator it;
for(it=memo.begin();it!=memo.end();it++) {
string t = *it;
if(temp.find(t) != string::npos) {
MAX = max(MAX,(int)(t.size()));
}
}
memo.clear();
return an + bn - MAX - MAX;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
//handle I/O here...
int T;
string a,b;
cin >> T;
getchar();
while(T--) {
cin >> a >> b;
cout << solve(a,b) << "\n";
}
//print your result here.
return 0;
}
For I/O, write the input in file named 'input.txt' located in the place where you would save/run this code. You will have your output in file named 'output.txt'.
A String is given as an input which consists of numbers and I want to convert it into integer arrays in C++.
#include <string>
#include <iostream>
#include <sstream>
using std::string;
using std::stringstream;
using std::cout;
using std::endl;
int main(int argc,char** argv) {
string num="-24 2 90 24 50 76";
stringstream stream(num);
while(stream){
int n;
stream>>n;
cout<<n<<endl;
}
return 0;
}
Output(GCC) :
-24 2 90 24 50 76 76
Why am i getting extra value and what is the efficient to convert them into integer array ?
UPDATE:
What if the string stream contains delimiter other than space, How to parse this?
For eg:
string num="-24,2,90,24,50,76";
The end of file condition is not set upon a succesful parse, you have to check the state of the stream after parsing.
The second 76 is basically just pure chance. An unsuccesful parse leaves the target operand untouched, and because you did not initialize n, it can be anything.
A quickfix:
stream>>n;
if (stream)
cout<<n<<endl;
A cleaner fix:
int n;
while(stream >> n){
cout<<n<<endl;
}
To store those integers, the canonical way is to use std::vector if the number of elements is unknown. An example usage:
std::vector<int> values;
int n;
while(stream >> n){
...do something with n...
values.push_back(n);
}
However, you can use iterators over streams and use the following:
// Use std::vector's range constructor
std::vector<int> values(
(std::istream_iterator<int>(stream)), // begin
(std::istream_iterator<int>())); // end
Another means of dealing with a character separated integers list using a vector, which is even perhaps a little more simplistic is more like this:
string str = "50,2,25,38,9,16";
vector<int> ints;
stringstream ss(str);
int n;
char ch;
while(ss >> n) {
if(ss >> ch)
ints.push_back(n);
else
ints.push_back(n);
}
that way you can move past any character separations (if they exist) first and then default back to grabbing the integers and adding them to the list if they don't (AKA the end of the list)
i don't know if you find the answer for your updated question or not. if you don't you can easily do it by the code
for (string::iterator it = num.begin(); it != num.end(); ++it) {
if (*it == ',') {
*it = ' ';
}
else continue;
}
this code removes all your colons and replaces them by space. then you can do just normally
i'm having problems reading a file and saving the values.
So the input file contains:
3 5
W2 R3 W3 R4
And what i want is this:
F = 3
P = 5
char Ac[] = {'W','R','W','R'};
int acc[] = {2,3,3,4};
I already have the F = 3 and P = 5 but i don't know how to separate the other Strings.
I hope you can help me!
You can read character by character, skipping whitespaces.
Or you could read in a string, then split the string:
std::string rw_text;
std::vector<char> Ac;
std::vector<int> acc;
//...
while (input_file >> rw_text)
{
const char letter = rw_text[0];
const int number = rw_text[1] - '0';
Ac.push_back(letter);
acc.push_back(number);
}
You could also use a struct to keep your letters and numbers together, like a pair.
struct Letter_Number
{
char letter;
int number;
friend std::istream& operator>>(std::istream& input, Letter_Number& ln);
};
std::istream& operator>>(std::istream& input, Letter_Number& ln)
{
input >> ln.letter;
input >> ln.number;
return input;
}
//...
std::vector<Letter_Number> database;
Letter_Number ln;
//...
while (input_file >> ln)
{
database.push_back(ln);
}
A structure will keep the letters associated with their numbers. In a parallel array, you could have different offsets or the pair won't line up.
Also, with having a structure, the letter and number will be on the processor's same data cache line, so your program will be more efficient. Otherwise the processor will have to load in the Ac array, get the value, then load in the acc array and load in the character; wasting time reloading the data cache.
I'm working on a project where I need to check for the correct input (n), I currently have a bit of code which won't allow string to be entered as it will ask again for a correct amount. I'm having trouble writing a code that won't allow float numbers to get through as it currently just ignores the float part of the input. I'm sorry if this is a simple question, but I haven't found a way to get around this yet.
for(int i=0; i<1; ++i)
{
string b1;
int e;
do
{
getline(cin,b1);
e=atoi(b1.c_str());
}
while(e==0 && b1!="0");
n=e; // where n is the user input
}
Assuming you consider anything with decimal point ('.') or using scientific notation with a negative exponent as a non-acceptable floating point number, just check if the entered string contains one of those:
std::string::iterator it;
if (b1.end() != std::find(b1.begin(), b1.end(), '.')
|| (b1.end() != (it = std::find_if(b1.begin(), b1.end(),
[](char c){ return c == 'e' || c == 'E'; })
&& it + 1 != b1.end()
&& '-' == it[1])) {
// deal with the string being a floating point number with a fractional part
}
Note, that this will consider, e.g., "10e-1" to be a bad value although it is actually just a fancy spelling of "1".
If you enter a float value then it will have a decimal point (.). As your input is a string hence you can do the following check :-
do
{
getline(cin,b1);
if(bi.find(".")!=b1.npos); // search if a decimal point is present or not
cout<<"wrong input";
else
e = stoi(b1); // stoi works similar to atoi but on strings
}
First thing you want to do is not repeat the code over and over ever time you want to read an integer. Make a function:
int getInt(std::istream & in)
This will take any input stream, cin, a file, a std::stringstream, whatever. Next we set up a few local variables we need.
{
std::string b1;
int e;
Now we build the input loop
while (std::getline(in, b1))
This will loop until the input stream fails. If it never fails and the user can't get their act togehter, we'll be here for a long long time. With Gilligan. The Skipper too. Maybe we can bum some money off of Mr. Howell for start-up seed capital, eh?
{
size_t pos;
Catch any exceptions thrown by the string -to-int conversion
try
{
Convert to int. pos will be updated with the character that ended the conversion. If it is not the end of the string, the string does not contain an int. If it does contain an int, we exit the function and return the int.
e = std::stoi(b1, &pos);
if (pos == b1.length())
{
return e;
}
}
We don't really need to do anything in the catch block. You could output a message to instruct or mock the user if you wish.
catch (...)
{
}
}
If we got here, the IO stream failed and we need to let folks know. Throw an exception.
// IO failure. throw exception
}
Usage is simple:
int value = getInt(cin);
You may wish to wrap the call in an try-catch block to catch the IO failure exception. cin's failure cases are pretty weird and usually fatal, though.
When calling getInt on a file you will want to handle things more carefully because end of file is a common occurrence.
All together without the running commentary:
int getInt(std::istream & in)
{
std::string b1;
int e;
while (std::getline(in, b1))
{
size_t pos;
try
{
e = std::stoi(b1, &pos);
if (pos == b1.length())
{
return e;
}
}
catch (...)
{
}
}
// IO failure. throw exception
}
You can use std::stringstream for this purpose :-
for(int i=0; i<1; ++i)
{
string b1;
char c=' ';
int e=0, check=0;
do
{
getline (cin, b1);
stringstream ss(b1);
ss >> check;
if(ss>>c)
cout << "bad input";
else
e=check;
}
while(e==0 && b1!="0");
n=e;
}
I have a file with data listed as follows:
0, 2, 10
10, 8, 10
10, 10, 10
10, 16, 10
15, 10, 16
17, 10, 16
I want to be able to input the file and split it into three arrays, in the process trimming all excess spaces and converting each element to integers.
For some reason I can't find an easy way to do this in c++. The only success I've had is by inputting each line into an array, and then regexing out all the spaces and then splitting it up. This entire process took me a good 20-30 lines of code and its a pain to modify for say another separator(eg. space), etc.
This is the python equivalent of what I would like to have in C++:
f = open('input_hard.dat')
lines = f.readlines()
f.close()
#declarations
inint, inbase, outbase = [], [], []
#input parsing
for line in lines:
bits = string.split(line, ',')
inint.append(int(bits[0].strip()))
inbase.append(int(bits[1].strip()))
outbase.append(int(bits[2].strip()))
The ease of use of doing this in python is one of the reasons why I moved to it in the first place. However, I require to do this in C++ now and I would hate to have to use my ugly 20-30 line code.
Any help would be appreciated, thanks!
There's no real need to use boost in this example as streams will do the trick nicely:
int main(int argc, char* argv[])
{
ifstream file(argv[1]);
const unsigned maxIgnore = 10;
const int delim = ',';
int x,y,z;
vector<int> vecx, vecy, vecz;
while (file)
{
file >> x;
file.ignore(maxIgnore, delim);
file >> y;
file.ignore(maxIgnore, delim);
file >> z;
vecx.push_back(x);
vecy.push_back(y);
vecz.push_back(z);
}
}
Though if I were going to use boost I'd prefer the simplicity of tokenizer to regex... :)
There is really nothing wrong with fscanf, which is probably the fastest solution in this case. And it's as short and readable as the python code:
FILE *fp = fopen("file.dat", "r");
int x, y, z;
std::vector<int> vx, vy, vz;
while (fscanf(fp, "%d, %d, %d", &x, &y, &z) == 3) {
vx.push_back(x);
vy.push_back(y);
vz.push_back(z);
}
fclose(fp);
Something like:
vector<int> inint;
vector<int> inbase;
vector<int> outbase;
while (fgets(buf, fh)) {
char *tok = strtok(buf, ", ");
inint.push_back(atoi(tok));
tok = strtok(NULL, ", ");
inbase.push_back(atoi(tok));
tok = strtok(NULL, ", ");
outbase.push_back(atoi(tok));
}
Except with error checking.
why not the same code as in python :) ?
std::ifstream file("input_hard.dat");
std::vector<int> inint, inbase, outbase;
while (file.good()){
int val1, val2, val3;
char delim;
file >> val1 >> delim >> val2 >> delim >> val3;
inint.push_back(val1);
inbase.push_back(val2);
outbase.push_back(val3);
}
std::getline allows you to read a line of text, and you can use a string stream to parse the individual line:
string buf;
getline(cin, buf);
stringstream par(buf);
char buf2[512];
par.getline(buf2, 512, ','); /* Reads until the first token. */
Once you get the line of text into the string, you can actually use any parsing function you want, even sscanf(buf.c_str(), "%d,%d'%d", &i1, &i2, &i3), by using atoi on the substring with the integer, or through some other method.
You can also ignore unwanted characters in the input stream, if you know they're there:
if (cin.peek() == ',')
cin.ignore(1, ',');
cin >> nextInt;
If you don't mind using the Boost libraries...
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
std::vector<int> ParseFile(std::istream& in) {
const boost::regex cItemPattern(" *([0-9]+),?");
std::vector<int> return_value;
std::string line;
while (std::getline(in, line)) {
string::const_iterator b=line.begin(), e=line.end();
boost::smatch match;
while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
return_value.push_back(boost::lexical_cast<int>(match[1].str()));
b=match[0].second;
};
};
return return_value;
}
That pulls the lines from the stream, then uses the Boost::RegEx library (with a capture group) to extract each number from the lines. It automatically ignores anything that isn't a valid number, though that can be changed if you wish.
It's still about twenty lines with the #includes, but you can use it to extract essentially anything from the file's lines. This is a trivial example, I'm using pretty much identical code to extract tags and optional values from a database field, the only major difference is the regular expression.
EDIT: Oops, you wanted three separate vectors. Try this slight modification instead:
const boost::regex cItemPattern(" *([0-9]+), *([0-9]+), *([0-9]+)");
std::vector<int> vector1, vector2, vector3;
std::string line;
while (std::getline(in, line)) {
string::const_iterator b=line.begin(), e=line.end();
boost::smatch match;
while (b!=e && boost::regex_search(b, e, match, cItemPattern)) {
vector1.push_back(boost::lexical_cast<int>(match[1].str()));
vector2.push_back(boost::lexical_cast<int>(match[2].str()));
vector3.push_back(boost::lexical_cast<int>(match[3].str()));
b=match[0].second;
};
};
If you want to be able to scale to harder input formats, you should consider spirit, boost parser combinator library.
This page has an example which almost do what you need (with reals and one vector though)