How to determine user input commands - c++

I am starting to write a command line converter and the only concern I have is user input (rest wont be hard). The program will have few commands like (convert 2 m to km), so when the user enters that, the program will output the converted value. My question is, what is the best way to parse user input and determine the command that user entered?. Should I divide user input into array of words and then pass to a function, so it can do something or there is another way?

I have written a few types of "simple parsers" (and several more advanced ones). From what you describe, if the commands are "convert 2 m to km", then you would simply need to split things on spaces.
Of course, if you allow "convert2mtokm" and "convert 2m to km" it gets a bit more difficult to deal with. Sticking to a "strict rule of there has to be a(t least one) space between words" makes life a lot easier.
At that point, you will have a vector<string> cmd that can be dealt with. So for example:
if (cmd[0] == "convert")
{
convert(cmd);
}
...
void convert(vector<string> cmd)
{
double dist = stod(cmd[1]);
string unit_from = cmd[2];
string unit_to = cmd[4];
if(cmd[3] != "to")
{
... print some error ...
}
double factor = unit_conversion(unit_from, unit_to);
cout << "that becomes " << dist * factor << " in " << unit_to << endl;
}

If you only have a few commands, it will be best to just strtok(input, ' '), which just splits up a string into an array of words in the command (assuming your command words are all separated by spaces). Then you can do some simple if/switch checks to see which command the user entered. For a larger number of commands (where some may be similar), you will probably need to implement or at least write out a DFA (deterministic finite automata).

An array of structures will be fine. The structure may be like this:
struct cmd
{
char **usrcmd;
void (*fc)();
};
Then you just have to iterate the array and compare the user input and the usrcmd[0] field (I assume the command is the first word).
However this solution is not the best way to go if you have a lot of user commands to handle.

Related

How to fix binary search algorithm?

Ok so i have been learning binary search. My teacher has given me a problem on codeforces and it always fails on test 2. Here is the problem:
In this problem jury has some number x, and you have to guess it. The number x is always an integer from 1 and to n, where n
is given to you at the beginning.
You can make queries to the testing system. Each query is a single integer from 1
to n
. Flush output stream after printing each query. There are two different responses the testing program can provide:
the string "<" (without quotes), if the jury's number is less than the integer in your query;
the string ">=" (without quotes), if the jury's number is greater or equal to the integer in your query.
When your program guessed the number x
, print string "! x", where x
is the answer, and terminate your program normally immediately after flushing the output stream.
Your program is allowed to make no more than 25 queries (not including printing the answer) to the testing system.
Input
Use standard input to read the responses to the queries.
The first line contains an integer n
(1≤n≤pow(10,6) — maximum possible jury's number.
Following lines will contain responses to your queries — strings "<" or ">=". The i
-th line is a response to your i-th query. When your program will guess the number print "! x", where x
is the answer and terminate your program.
The testing system will allow you to read the response on the query only after your program print the query for the system and perform flush operation.
Output
To make the queries your program must use standard output.
Your program must print the queries — integer numbers xi
(1≤xi≤n), one query per line (do not forget "end of line" after each xi
). After printing each line your program must perform operation flush.
And here is my code:
#include <iostream>
using namespace std;
int main()
{
int n;
string s;
int k=0;
cin>>n;
int min=1,max=n;
int a;
while(k==0)
{
if(max==min+1)
{
cout<<"! "<<min;
k=1;
break;
}
a=(min+max)/2;
cout<<a<<endl;
cin>>s;
if(s==">=")
min=a;
else
max=a;
}
}
I dont know what test 2 is, but i would be happy to hear ideas as to where my programs is wrong. My guess is its something with the number of guesses. Thanks in advance!
I have tried variations of the loop written above, but they all give the same result.

Find out the average value of inputted integers

I managed to get this program to work. If the user types an unfixed amount of integers, the program will calculate the average value of it. But I need to end it with <Ctrl-D> in my terminal (end of file) in order for it to work. Why can I not just press enter for it to work?
I also believe that I've used an unnecessary amount of variables. Can it be narrowed down to maybe 2 variables?
#include <iomanip>
#include <iostream>
using namespace std;
int main ()
{
int digit {};
int res {};
int counter {};
cout << "Type in integers: ";
while (cin >> digit)
{
counter ++;
res += digit;
}
cout << "The mean was " << setw(1) << setprecision(1) << fixed << static_cast<double>(res) / static_cast<double>(counter) << endl;
return 0;
}
Why can I not just press enter for it to work?
Because that's not how the overloaded >> formatted extraction operator works. This operator skips over an unlimited amount of whitespace characters, including newline characters, until it reads the integer. It's simply how it works: it will read newlines and spaces, after newlines, and spaces, until it sees a digit. That's its mission in life: read and skip over spaces and newlines until it reads at least one digit. It never gets tired of reading newlines and spaces, and will keep going as long that's the case.
To handle input in the fashion you describe requires a completely different approach: using std::getline to read a single line of input into a std::string, up until the next newline character. Then, once that's done, you can check if the std::string is empty, which means that no input was entered, and then terminate; otherwise take the input in std::string and convert it to an int value (using std::stoi, std::from_chars, or a std::istringstream -- take your pick), and then proceed with the existing algorithm.
Can it be narrowed down to maybe 2 variables?
How do you expect to do that? Hard, immutable logic dictates that you must keep track of at least two discrete values: the total sum and the number of values read. But then you just ran out of variables. You have no more variables to use for storing the next read value (if there is one), using whatever approach you chose to use. So, you can't do it. Rules of logic require the use of at least three variables, possibly more depending on how fancy and robust you want your input validation to work.

How to check if number from stdin is less than the numeric limit of a given type?

I have received a task that does not actually specify, what range of input one of my functions should expect (only, that it is always going to be a positive integer), and the input is decided runtime. Can I somehow test if the type I selected can actually hold the value it was fed to?
An illustration of what I am hoping to do:
char test;
std::cin >> test;
if(MAGIC)
{
std::cout << "Error." << std::endl;
}
With the magical part (or even the preceeding line) being the test I'm looking for.
It should work like this:
stdin: 100 -> no output
stdin: 1000000 -> Error.
For most data types you can check the error state of the input stream as described here. However, this would not work for some other types, such as char from your post, because std::cin >> test would read data as a single character, i.e. '1' which is not what you need to achieve.
One approach is to read the number into std::string, and compare it to the max() obtained through limits:
std::string max = std::to_string(std::numeric_limits<char>::max());
std::string s;
std::cin >> s;
bool cmp = (s.size() == max.size()) ? (s <= max) : (s.size() < max.size());
std::cout << s << " " << cmp << std::endl;
Demo.
Note: The above code makes an assumption that the data entered is a number, which may be arbitrarily large, but must not contain characters other than digits. If you cannot make this assumption, use a solution from this Q&A to test if the input is numeric.
I think the answer may be in https://stackoverflow.com/a/1855465/7071399 to know where to get the limits, then refer to https://stackoverflow.com/a/9574912/7071399 to get inspiration to your code (given you can use a long int or a char array to store the number and then check if it fits in the integer value).

C++ take a letter from a file

I'm working on a C++ file. And this is what I've got: The user has to type the name of a file, e.g. file1.txt, and I have to count the letters in that file.
All of this is working but: after "x" letters, I have to take the next letter and show it on the screen. I don't really know how to do this?
I think it has to be an if-statement and it has to start like this:
if (count_letters = x){
}
But I'm really lost after that.
Thanks !
It should be
if (count_letters >= x)
Note that the == operator compares two values, whilst = assigns a value to a variable. Then in your if body you'd probably just do something along the lines of
std::cout << letters[x] << std::endl;

How to capture 0-2 groups in C++ regular expressions and print them?

Edit 3
I went to the good'ol custom parsing approach as I got stuck with the regular expression. It didn't turn out to be that bad, as the file contents can be tokenized quite neatly and the tokens can be parsed in a loop with a very simple state machine. Those who want to check, there's a snippet of code doing this with range-for, ifstream iterators and custom stream tokenizer at my other question in Stackoverflow here. These techniques lessen considerably the complexity of doing a custom parser.
I'd like to tokenize file contents in first part in capture groups of two and then just line by line. I have like a semi-functional solution, but I'd like to learn how to make this better. That is, without "extra processing" to make-up my lack of knowledge with capture groups. Next some preliminaries and in the end a more exact question (the line
const std::regex expression("([^:]+?)(^:|$)");
...is the one I'd like to ask about in combination with processing the results of it).
The files which are basically defined like this:
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS
[DATA ROW 1]
[DATA ROW 2]
...
[DATA ROW n]
Where each of the data rows consists of a certain number of either integers or floating point numbers separated by whitespace. Each row having as many numbers as the others (e.g. each row could have four integers). So, the "interpretation section" basically tells this format in plain text in one row.
I have an almost working solution that reads such files like this:
int main()
{
std::ifstream file("xyz", std::ios_base::in);
if(file.good())
{
std::stringstream file_memory_buffer;
file_memory_buffer << file.rdbuf();
std::string str = file_memory_buffer.str();
file.close();
const std::regex expression("([^:]+?)(^:|$)");
std::smatch result;
const std::sregex_token_iterator end;
for(std::sregex_token_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
std::cout << (*i) << std::endl;
}
}
return EXIT_SUCCESS;
}
With the regex defined expression, it now prints the <value> parts of the definition file, then the interpretation part and then the data rows one by one. If I change the regex to
"([^:]+?)(:|$)"
...it prints all the lines tokenized in groups of one, almost like I would like to, but how tokenize the first part in groups of two and the rest line by line?
Any pointers, code, explanations are truly welcomed. Thanks.
EDIT:
As noted to Tom Kerr already, but some additional points, this is also a rehearsal, or coding kata if you will, to not to write a custom parser, but to see if I could -- or we could :-) -- accomplish this with regex. I know regex isn't the most efficient thing to do here, but it doesn't matter.
What I'd hope to have is something like a list of tuples of header information (tuple of size 2), then the INTERPRET line (tuple of size 1), which I could use to choose a function on what to do with the data lines (tuple of size 1).
Yep, the "HOW TO INTERPRET" line is contained in a set of well-defined strings and I could just read line by line from the beginning, splitting strings along the way, until one of the INTERPRET lines is met. This regex solution is not the most efficient method, I know, but more like coding kata to get myself to write something else than customer parsers (and it's quite some time I've write in C++ the last time, so this is rehearsing otherwise too).
EDIT 2
I have managed to get access to the tuples (in the context of this question) by changing the iterator type, like so
const std::sregex_iterator end;
for(std::sregex_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
std::cout << "0: " << (*i)[0] << std::endl;
std::cout << "1: " << (*i)[1] << std::endl;
std::cout << "2: " << (*i)[2] << std::endl;
std::cout << "***" << std::endl;
}
Though this is still way off what I'd like to have, there's something wrong with the regular expression I'm trying ot use. In any event, this new find, another kind of iterator, helps too.
I believe the re you are attempting is this:
TEST(re) {
static const boost::regex re("^([^:]+) : ([^:]+)$");
std::string str = "a : b";
CHECK(boost::regex_match(str, re));
CHECK(!boost::regex_match("a:a : bbb", re));
CHECK(!boost::regex_match("aaa : b:b", re));
boost::smatch what;
CHECK(boost::regex_match(str, what, re, boost::match_extra));
CHECK_EQUAL(3, what.size());
CHECK_EQUAL(str, what[0]);
CHECK_EQUAL("a", what[1]);
CHECK_EQUAL("b", what[2]);
}
I'm not sure I would recommend regex in this instance though. I think you'll find simply reading a line at a time, splitting on :, and then trimming the spaces more manageable.
I guess if you can't depend the below line as a sentinel, then it would be more difficult. Usually I would expect a format like this to be obvious from that line, not the format of each line of the header.
HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS