I can't understand how I would do this.
The input will be:
3
13894
30-something
-Ex42
and the output needs to be:
13894
30
Ex42
The main assignment is to make a function that converts a duodecimal number into the decimal format. I have figured that part out and don't need help with it. I've basically cut out all the code surrounding the duodecimal conversion and just included the stuff I can't figure out.
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int to_decimal(const string& str);
int main () {
string str; // Initializes string str for input
cin.ignore (256, '\n'); //ignores the 3 from the input
while (getline(cin, str)) {
//runs str through to_decimal and outputs
cout << to_decimal(str) << endl;
}
}
int to_decimal(const string& str) {
int f = 0;
string localString; // Initialize local string variable
//sets local string to the same as inputted string
localString = str; //used for local string erasing
//This is the idea I have been working on and I cant figure it out
for (unsigned x = 0; x < localString.length(); x++) {
f = localString.at(x);
if (isdigit(f)) {
} else if (f == 'E'){
} else if (f == 'e') {
} else if (f == 'X') {
} else if (f == 'x') {
} else if (f == '-') {
} else if (f == ' ') {
} else {
f = localString.length() - x;
localString.erase(x, f);
break;
}
}
}
I am a bit confused. You say that you need to convert duodecimal numbers to decimal, however in your sample output only the line that has Ex is converted, yet 30-something stays 30, as if it is not converted - and 30 in duodecimal is 36 in decimal. Same for the number 13894.
Assuming that you really want to convert all of the lines from duodecimal to decimal, you can base your solution on the standard library function std::stoi() which can convert a string from most number bases up to 36. It requires that the digits bigger than 9 are encoded using the letters in alphabetic order - A to Z. So you need to simply convert all you x to a and all you e to b. Example:
int to_decimal(const string& str) {
bool foundDigit = false;
std::string transformedString;
for (auto c : str) {
if (std::isdigit(c) || c == 'E' || c =='e' || c == 'X' || c == 'x') {
foundDigit = true;
// If needed, convert the character.
if (c == 'E' || c == 'e') {
c = 'b';
} else if (c == 'X' || c == 'x') {
c = 'a';
}
transformedString += c;
} else if (foundDigit) {
// Skip everything to the end of the line, if we've already found some digits
break;
}
}
return std::stoi(transformedString, 0, 12);
}
If you just want to extract the characters and then do the conversion yourself, then you can do something like this:
#include <iostream>
#include <string>
#include <sstream>
bool isNumber(const char c)
{
switch (c) {
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '0':
case 'e':
case 'E':
case 'x':
case 'X':
case '-':
return true;
default:
return false;
}
}
std::string getNumber(std::istream& in)
{
std::stringstream s;
for (char c;in.get(c);)
{
if (isNumber(c)) {
s << c;
break;
}
}
for (char c;in.get(c);)
{
if (!isNumber(c))
break;
s << c;
}
return s.str();
}
int main()
{
std::string bla = "3\n13894\n 30-something\n-Ex42\n";
std::stringstream klaf{ bla };
for (std::string s;(s = getNumber(klaf)) != "";) //<- use a local stringstream as input to test
//for (std::string s;(s = getNumber(std::cin)) != "";) //<- use std::cin for input
{
std::cout << s << '\n';
}
}
This outputs:
3
13894
30-
e
-Ex42
So, not exactly what you were after, but it should at least get you a starting point to improve from. For example, you may want to remove - from isNumber and then change to logic in getNumber to only accept it as the first character in a new number.
Related
I found a project done a few years ago found here that does some simple command line parsing. While I really like it's functionality, it does not support parsing special characters, such as <, >, &, etc. I went ahead and attempted to add some functionality to parse these characters specifically by adding some of the same conditions that the existing code used to look for whitespace, escape characters, and quotes:
bool _isQuote(char c) {
if (c == '\"')
return true;
else if (c == '\'')
return true;
return false;
}
bool _isEscape(char c) {
if (c == '\\')
return true;
return false;
}
bool _isWhitespace(char c) {
if (c == ' ')
return true;
else if(c == '\t')
return true;
return false;
}
.
.
.
What I added:
bool _isLeftCarrot(char c) {
if (c == '<')
return true;
return false;
}
bool _isRightCarrot(char c) {
if (c == '>')
return true;
return false;
}
and so on for the rest of the special characters.
I also tried the same approach as the existing code in the parse method:
std::list<string> parse(const std::string& args) {
std::stringstream ain(args); // iterates over the input string
ain >> std::noskipws; // ensures not to skip whitespace
std::list<std::string> oargs; // list of strings where we will store the tokens
std::stringstream currentArg("");
currentArg >> std::noskipws;
// current state
enum State {
InArg, // scanning the string currently
InArgQuote, // scanning the string that started with a quote currently
OutOfArg // not scanning the string currently
};
State currentState = OutOfArg;
char currentQuoteChar = '\0'; // used to differentiate between ' and "
// ex. "sample'text"
char c;
std::stringstream ss;
std::string s;
// iterate character by character through input string
while(!ain.eof() && (ain >> c)) {
// if current character is a quote
if(_isQuote(c)) {
switch(currentState) {
case OutOfArg:
currentArg.str(std::string());
case InArg:
currentState = InArgQuote;
currentQuoteChar = c;
break;
case InArgQuote:
if (c == currentQuoteChar)
currentState = InArg;
else
currentArg << c;
break;
}
}
// if current character is whitespace
else if (_isWhitespace(c)) {
switch(currentState) {
case InArg:
oargs.push_back(currentArg.str());
currentState = OutOfArg;
break;
case InArgQuote:
currentArg << c;
break;
case OutOfArg:
// nothing
break;
}
}
// if current character is escape character
else if (_isEscape(c)) {
switch(currentState) {
case OutOfArg:
currentArg.str(std::string());
currentState = InArg;
case InArg:
case InArgQuote:
if (ain.eof())
{
currentArg << c;
throw(std::runtime_error("Found Escape Character at end of file."));
}
else {
char c1 = c;
ain >> c;
if (c != '\"')
currentArg << c1;
ain.unget();
ain >> c;
currentArg << c;
}
break;
}
}
What I added in the parse method:
// if current character is left carrot (<)
else if(_isLeftCarrot(c)) {
// convert from char to string and push onto list
ss << c;
ss >> s;
oargs.push_back(s);
}
// if current character is right carrot (>)
else if(_isRightCarrot(c)) {
ss << c;
ss >> s;
oargs.push_back(s);
}
.
.
.
else {
switch(currentState) {
case InArg:
case InArgQuote:
currentArg << c;
break;
case OutOfArg:
currentArg.str(std::string());
currentArg << c;
currentState = InArg;
break;
}
}
}
if (currentState == InArg) {
oargs.push_back(currentArg.str());
s.clear();
}
else if (currentState == InArgQuote)
throw(std::runtime_error("Starting quote has no ending quote."));
return oargs;
}
parse will return a list of strings of the tokens.
However, I am running into issues with a specific test case when the special character is attached to the end of the input. For example, the input
foo-bar&
will return this list: [{&},{foo-bar}] instead of what I want: [{foo-bar},{&}]
I'm struggling to fix this issue. I am new to C++ so any advice along with some explanation would be great help.
When you handle one of your characters, you need to do the same sorts of things that the original code does when it encounters a space. You need to look at the currentState, then save the current argument if you are in the middle of one (and reset it since you no longer are in one).
So i am writing a calculator as an exercise in c++, were you first select operators +, -, * or / by inputting a, s, m or d. The calculator works fine, except for a filter i set up to respond with an error if the user inputs something other than a, s, m or d. The filter is an if statement:
if(Opperator=='a'||'s'||'m'||'d')
{
//some code
}
else
{
//"Operatorfault"
cout <<"opperatorfeil";
}
Even though the "operator" has other char values than those the if statement is suppose to execute, the code within the if statement is still executed. The whole code is below. The outputs and variables are in Norwegian, but i have tried to translate in the comments.
#include <iostream>
using namespace std;
//The calculator function
int Kalkulator(int IN1, int IN2, char Opperator)
{
int Svar;
//Detects witch operator the user choose, and preforms the assigned operation
if(Opperator=='a')
{
Svar=IN1+IN2;
}
if(Opperator=='s')
{
Svar=IN1-IN2;
}
if(Opperator=='m')
{
Svar=IN1*IN2;
}
if(Opperator=='d')
{
Svar=IN1/IN2;
}
//Returns the answer
return Svar;
}
int main()
{
//Input a, s, m or d for addition, subtraction, multiplication or division, respectively
cout <<"Skriv \"a\" for addisjon, \"s\" for subtraksjon, \"m\" for multipliksjon, og \"d\" for divisjon";
cout <<endl;
cout <<endl;
char Opperator;
cin >>Opperator;
cout <<endl;
//Checks if the input is valid
if(Opperator=='a'||'s'||'m'||'d')
{
cout <<"Skriv inn det første tallet du vil gjøre opperasjonen på, trykk derreter enter, og skriv inn det andre";
cout <<endl;
cout <<endl;
int IN1;
int IN2;
cin >>IN1;
cin >>IN2;
cout <<endl;
//"The answer is"
cout << "Svaret er: ";
//Calls the calculator function, and inputs the values it has gathered, then prints the answer
cout <<Kalkulator(IN1, IN2, Opperator);
}
else
{
//"Operatorfault"
cout <<"opperatorfeil";
}
return 0;
}
The error is in your if statement. In C++, when you are comparing the same variable to multiple values, for example if opperator is a, m, s, d, you need to restate the variable for each comparison.
if( Opperator=='a' || Opperator=='s' || Opperator=='m' || Opperator=='d' )
Instead of your current if statement.
Also, as a tip, a switch statement is much better in these cases, you can simply state
int ans;
switch (customerPackage) {
case 'a':
ans = int1 + int2;
case 's':
ans = int1 - int2;
case 'd':
ans = int1 * int2;
case 'm':
ans = int1 / int2;
default:
string ans;
ans = "invalid input";
}
cout <<ans;
This is wrong:
if(Opperator=='a'||'s'||'m'||'d')
you can NOT test for equality (or inequality) like this. The code executes as the equivalent of
if (Operator == (result of boolean ORs))
You have to test for equality individually:
if ((op == 'a') || (op == 's') || etc...)
Why not just break it out like so,
if (Opperator == 'a' ||
Opperator == 's' ||
Opperator == 'm' ||
Opperator == 'd')
{
// Good values
}
else
{
// Bad values
}
if(Opperator=='a'||'s'||'m'||'d')
It checks whether Opperator is equal to 'a', if not then 's' always returns true and so all logic becomes true.
You can use if statement:
if (Opperator == 'a' || Opperator == 's' || Opperator == 'm' || Opperator == 'd') {
// my calc works well
} else {
// again my calc works well
}
OR you can use switch:
switch(Opperator) {
case 'a':
case 's':
case 'm':
case 'd': // do normal operation here
break;
default: // error handle
break;
}
You must test each char for equality:
if(Opperator=='a'||Opperator=='s'||Opperator=='m'||Opperator=='d') {
...execute
} else {
...execute something else
}
If you want to be fancy you can use algorithm::anyOf().
#include <algorithm>
const std::vector<char> validValues{'a','s','m','d'};
if(any_of(validValues.begin(),
validValues.end(),
[&](const char &x) { return x == Opperator; }) {
// good values
} else {
// bad values
}
I'm learning C++ using B. Stroustrup's PPP, 1st edition. I was testing this simple calculator after completing Q9. from the Ch.7 exercises by giving random inputs to the calculator.
I'm using Visual Studio 2013 and this is the complete code of the calculator I'm using -
// This program is an simple calculator
/*
----------------------------------------------------------------------------------------
>>> Grammar used in this program to handle expressions and features <<<
Calculator:
Statement
Quit
Print
Help
Calculator Statement
Print:
";"
Quit:
"q"
Statement:
Declaration
Assignment
Expression
Declaration:
"let" Name "=" Expression
"const" Name "=" Expression
Assignment:
"set" Name "=" Expression
Name:
string-literal-starting-with-alphabet-or-underscore-and-contains-only-alphabets-underscores-&-numbers
Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Primary
Term "*" Primary
Term "/" Primary
Term "%" Primary
Primary:
Number
Name
"(" Expression ")"
"+" Primary
"-" Primary
"pow(" Primary "," Primary ")"
"sqrt(" Primary ")"
Number:
floating-point-literal
Input comes from cin through Token_stream called ts, in the form of Tokens.
*/
#include "std_lib_facilities.h"
struct Token {
char kind; // kind of Token
double value; // for numbers: value of Token
string name; // for variables: name of variables
Token(char ch) :kind(ch), value(0) { }
Token(char ch, double val) :kind(ch), value(val) { }
Token(char ch, string var) :kind(ch), name(var) { }
};
class Token_stream {
public:
Token_stream() :full(0), buffer(0) { }
Token get(); // get Tokens from Token_stream
void unget(Token t) { buffer = t; full = true; } // putback Token into Token_stream
void ignore(char c); // ignore characters till c is found, including c
private:
bool full; // buffer status
Token buffer; // buffer to store single Token
};
// Token.kind symbolic constants
const char let = '#'; // for variale-declaration
const char set = '#'; // for assignment
const char constant = '!'; // for constant-declaration
const char quit = 'Q'; // quit application
const char print = ';'; // print expression-output
const char number = '8'; // for number
const char name = 'a'; // for variable-name
const char sqroot = 'R'; // square root
const char power = 'P'; // power/order
//const char variabletype = 'v'; // variable type in Variable
//const char constanttype = 'c'; // constant type in Variable
const char help = 'h'; // help - instructions/examples/features
const string declkey = "let"; // declaration keyword, like let x = 2; to declare a new variable x
const string assignkey = "set"; // assignment keyword, like set x = 3; where x is a declared variable
const string quit1key = "quit"; // quit keyword 1
const string quit2key = "exit"; // quit keyword 2
const string quit3key = "q"; // quit keyword 3
const string powerkey = "pow"; // for using power function
const string sqrtkey = "sqrt"; // for using square root function
const string constkey = "const";// for declaring a symbolic constant, not a variable
const string help1key = "H"; // help keyword 1
const string help2key = "h"; // help keyword 2
const string help3key = "help"; // help keyword 3
const string help4key = "HELP"; // help keyword 4
const string help5key = "Help"; // help keyword 5
Token Token_stream::get()
{
if (full) { full = false; return buffer; }
char ch;
cin.get(ch);
switch (ch) {
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '%':
case print:
//case quit:
//case let:
case '=': // during variable/constant-initialization, assignment
case ',': // pow(x , i);
return Token(ch);
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{ cin.unget();
double val;
cin >> val;
return Token(number, val);
}
default:
if (isalpha(ch) || ch == '_') { // check for alphabet
string s;
s += ch;
while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_')) s += ch; // store only alphabets, numbers & underscores
cin.unget();
if (s == declkey) return Token(let); // is current statement a variable-declaration?
if (s == constkey) return Token(constant); // is current statement a constant-declaration?
if (s == assignkey) return Token(set); // is current statement an assignment?
if (s == quit1key || s == quit2key || s == quit3key) return Token(quit); // user wants to quit?
if (s == help1key || s == help2key || s == help3key || s == help4key || s == help5key) return Token(help); // user needs help?
if (s == sqrtkey) return Token(sqroot); // square root of expression
if (s == powerkey) return Token(power); // pow(x,i) = x^i = x*x*...*x (i times)
return Token(name, s); // it's a variable name then
}
else if (isspace(ch)){
if (ch == '\n')
return Token(print);
else
return get();
}
error("Bad token");
}
}
void Token_stream::ignore(char c) // ignore all characters till & including c
{
if (full && c == buffer.kind) {
full = false;
return;
}
full = false;
char ch;
while (cin.get(ch))
if (ch == c) return;
}
struct Variable {
string name;
double value;
char type;
Variable(string n, double v, char c) :name(n), value(v), type(c) { }
};
class Table {
public:
double get(string s);
void set(string s, double d);
double declare(string s, double val, char type);
bool is_declared(string s);
private:
vector<Variable> var_table;
};
Table symbol_table;
double Table::get(string s) // get value of declared variable with name s
{
for (int i = 0; i < var_table.size(); ++i)
if (var_table[i].name == s) return var_table[i].value;
error("get: undefined name ", s);
}
void Table::set(string s, double d) // set value of declared variable with name s to d
{
for (int i = 0; i <= var_table.size(); ++i)
if (var_table[i].name == s) {
if (var_table[i].type == constant)
error("set: can't change the value of a constant");
var_table[i].value = d;
return;
}
error("set: undefined name ", s);
}
bool Table::is_declared(string s) // check if a variable with name s is declared
{
for (int i = 0; i < var_table.size(); ++i)
if (var_table[i].name == s) return true;
return false;
}
double Table::declare(string s, double d, char type)
{
if (is_declared(s))
error("declare: variable already exists ", s);
var_table.push_back(Variable(s, d, type));
return d;
}
Token_stream ts;
double expression();
double primary() // Primary:
{
Token t = ts.get();
switch (t.kind) {
case '(': // "(" Expression ")"
{
double d = expression();
t = ts.get();
if (t.kind != ')') error("primary: '(' expected");
return d;
}
case '-': // "-" Primary
return -primary();
case '+': // "+" Primary
return primary();
case number: // floating-point-number
return t.value;
case name: // value of variable with name t.name
return symbol_table.get(t.name);
case sqroot: // sqrt(x) or "sqrt" Primary
{
double d = primary();
if (d < 0) error("negative square root");
return sqrt(d);
}
case power:
{
t = ts.get(); // check for '('
if (t.kind != '(')
error("power_primary: '(' expected");
double d1 = expression();
t = ts.get();
if (t.kind != ',')
error("power_primary: ',' expected");
double d2 = expression();
t = ts.get();
if (t.kind != ')')
error("power_primary: ')' expected");
int i = narrow_cast<int>(d2);
//if (d2 - int(d2) > 0)
// error("power_primary: 2nd argument invalid, must be an integer");
//if (d1 == 0 && d2 == 0)
// error("power_primary: pow(0,0) is undefined");
return pow(d1, i);
}
default:
error("primary expected");
}
}
double term() // Term:
{
double left = primary(); // Primary
while (true) {
Token t = ts.get();
switch (t.kind) {
case '*': // Term "*" Primary
left *= primary();
break;
case '/': // Term "/" Primary
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
break;
}
case '%': // Term "%" Primary
{
double d = primary();
int i1 = narrow_cast<int>(left);
int i2 = narrow_cast<int>(d);
if (i2 == 0)
error("term: modulo by zero");
left = i1%i2;
break;
}
default: // return term-value
ts.unget(t);
return left;
}
}
}
double expression() // Expression:
{
double left = term(); // Term
while (true) {
Token t = ts.get();
switch (t.kind) {
case '+': // Expression "+" Term
left += term();
break;
case '-': // Expression "-" Term
left -= term();
break;
default: // return expression-value
ts.unget(t);
return left;
}
}
}
double declaration() // assuming "let" has been found
{
Token t = ts.get();
char type;
type = t.kind;
t = ts.get();
if (t.kind != name) error("declaration: name expected in declaration"); // check if the Token read is a name
string name = t.name;
Token t2 = ts.get();
if (t2.kind != '=') error("declaration: '=' missing in declaration of ", name); // expecting a '=' after variable name
double d = expression(); // everything right so far, get the initial value of the variable
return symbol_table.declare(name, d, type); // store new variable/constant in vector names
}
double assignment() // assuming "set" has been found
{
Token t = ts.get();
if (t.kind != name) // check if the Token read is a name
error("assignment: name expected in declaration");
string var = t.name;
if (!symbol_table.is_declared(var)) // check if the variable is declared or not
error("assignment: can't assign value to an undeclared variable");
t = ts.get(); // check for '='
if (t.kind != '=')
error("assignment: '=' expected in declaration of ", var);
double newval = expression(); // get new value of variable var
symbol_table.set(var, newval); // set new value
return newval;
}
double statement()
{
Token t = ts.get();
switch (t.kind) {
case let: // is it a variable-declaration?
case constant: // is it a constant-declaration?
ts.unget(t);
return declaration();
case set: // or an assignment?
return assignment();
default: // or an expression?
ts.unget(t);
return expression();
}
}
void clean_up_mess()
{
ts.ignore(print); // ignore characters till and including 'print' character
}
const string prompt_str = "> ";
const string result_str = "= ";
void calculate()
{
// Welcome message
cout << " This program is a basic calculator\n"
<< " To know more use - 'help'\n"
<< " To quit use - 'quit' or 'exit'\n\n";
while (true)
try {
cout << prompt_str;
Token t = ts.get(); // get a token
while (t.kind == print) t = ts.get(); // eat all 'print' tokens
if (t.kind == quit) return; // 'quit' token?
else if (t.kind == help){
// Instructions to use calculator
cout << "\n INSTRUCTIONS TO USE -\n"
<< "\t1. Operations supported: +, -, *, /, % (last one for integers only), sqrt(x), pow(x,y) (y is an integer).\n"
<< "\t2. Use expressions like 1+2/3*4-5, followed by " << print << " to terminate expression.\n"
<< "\t3. Use square brackets or parenthesis or both in expressions as usual, for example, (1-2)*{(3-4)/2}.\n";
// Features
cout << "\n FEATURES -\n"
<< "\t1. Evaluate multiple expressions at once. Enter more than one expressions in a line and see them get evaluated at once.\n"
<< "\t2. Use variables for easy calculation. Declare them like this, \"let x = 6;\" or write any expression in place of '6'.\n"
<< "\t3. Assign new values to already declared variables like this, \"set x = 3;\"\n"
<< "\t4. Use constants like 'pi' & 'e' in statements instead of remembering their values.\n"
<< "\t5. Declare your own constants like this, \"const pi = 3.1415\"\n"
<< "\t6. Ask for help anytime, use \"Help\" or \"help\" or \"HELP\" or \"h\" or \"H\"\n"
<< "\t7. Want to quit, just type \"quit\" or \"exit\"\n"
<< "\n";
//continue;
}
else{
ts.unget(t); // some other token was read, so unread it, put it back in Token_stream
cout << result_str << statement() << endl; // read 'statement' from the input stream, and evaluate it, and print its result
}
}
catch (runtime_error& e) {
cerr << e.what() << endl;
clean_up_mess();
}
catch (...){
cerr << "Oops, unknown exception" << endl;
clean_up_mess();
}
}
int main()
{
try {
// pre-defined symbolic constants
symbol_table.declare("k", 1000, constant); // k = 1000 like pi = 3.1415926535(not defined here)
calculate();
char c;
while (cin.get(c) && c != print && c != '\n');
cout << "\n\n You've now exited the program.\n"
<< " Enter x to close this window.\n\n ";
while (cin >> c && c == 'x')
break;
return 0;
}
catch (exception& e) {
cerr << "exception: " << e.what() << endl;
char c;
while (cin >> c && c != print);
return 1;
}
catch (...) {
cerr << "Oops: Unknown exception\n";
char c;
while (cin >> c && c != print);
return 2;
}
}
But I've found that the program gives this error
whenever I provide it input of the form "some_real_number_here e string_starting_with_alphabet", without any whitespace, with last string being optional and it happens with e only and not with any other alphabet (hopefully because I haven't tried each & every combination of numbers & alphabets).
What is this error? How to resolve this?
Here is the library std_lib_facilities.h .
If you're testing the program too, then at the end of every input/expression to the program, have ; for letting the program clean_up_mess() easily.
Hopefully, this is the file mentioned in the error window, isctype.c.
For example -
Input: 2e; or 4easdf123; Output: The above mentioned error
Other weird outputs -
Input: 2e12; Output: 2e+12
Input: 3e1; Output: 30
Edit: It might be the case (discussed in comments) that Token_stream::get() function when trying to read a floating-point number like 2e+11, gives error because of expecting a number whenever >> sees something like this - "number e anything" (without whitespace) and when it finds an alphabet in anything instead of an integer, it throws an exception.
I can't get the right output.. please help me..
and it should return false when I put number as the first character for the name
like this ,
Enter the name of the first rectangle: rec 1a
Invalid input. Type 'rec' following by the name or 'stop' if done.
Try again! Enter the name of the first rectangle: rec a
Enter a's bottom left x and y coords: 9 3
Enter a's length and height: 2 8
i am only allow to use these 3, not anything else..
#include <iostream>
#include <string>
#include <vector>
and my code is
bool promptread_rec(const string & prompt, const string & invalid, const string & usedname, string & input, vector<Rectangle> & list)
{
cout << prompt;
getline(cin, input);
if (input == "stop")
{
return true;
}
else if (input.substr(0,4) != "rec ")
{
cout << invalid << endl;
return false;
}
else if (input[4] == '0' || input [4] == '1' || ......)
{
cout << invalid << endl;
return false;
}
else if (list.size() > 0)
{
for (int i = 0; i < list.size(); i++)
{
if (input == list[i].getName())
{
cout << usedname;
return false;
}
}
return true;
}
else
{
return true;
}
}
is there a faster way to do it?? need to avoid all numbers e.g. 0,1,2,3,...,9
From the header cctype, you may use the function isalpha(c) on the first character of the string, like:
string a = "a1234";
assert(isalpha(a.at(0)) == true);
a = "1234";
assert(isalpha(a.at(0)) == true);
Just remember to access a.at(0) only if the string is not empty or else it will throw a std::out_of_range exception
References:
http://www.cplusplus.com/reference/cctype/isalpha/
http://www.cplusplus.com/reference/cassert/assert/
http://www.cplusplus.com/reference/string/string/at/
Since you cannot use any other headers you have to implement your own functions, which is actually simple enough for ASCII characters:
bool IsLetter(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
bool IsDigit(char c) {
return c >= '0' && c <= '9';
}
Using these two helper functions you can write a function to test if a name is valid:
bool IsValidName(const std::string &name);
I leave this for you to implement.
I have to read in a csv file with 5 fields (int , char[], char[], char[], float) that looks like that :
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
I have to put the fields in a struct, and then put the struct after one line is complete, into a array of the struct type ...
for the learning effect, we are only allowed to use LOW-LEVEL coding, and only use functions like fgetc, strcpy and no strings, only char[]...
Now I made my algorithm to read the textfile character by character, but I have problems separating them correctly, putting them together again and assigning them to the struct fields correctly. Here is my Code:
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;
int main(int argc, char **argv)
{
struct Stud{
long matrnr;
char vorname[30];
char name[30];
char datum[30];
float note;
};
const int MAX = 30;
Stud stud;
Stud mystud[30]; // <<-- Array of "Stud" type
//memset((void*)mystud,0,sizeof(mystud) * sizeof(Stud));
int wordCounter(0);
int i(0); //thats the charCounter or index
int studentCounter(0);
char wort[MAX];
//int matrnr;
//char vorname[MAX];
//char name[MAX];
//char datum[MAX];
//float note;
FILE * pFile;
int cnr(0);
pFile=fopen("studentendaten.txt","r");
if (pFile==nullptr)
{
perror ("Fehler beim öffnen der Datei");
}
else
{
while (cnr != EOF)
{
(cnr=fgetc(pFile)) ;
if ((char)cnr == '\n') {
mystud[studentCounter] = stud;
studentCounter++;
continue;
}
if ((char)cnr == ';') {
wort[i] = '\0';
switch (wordCounter % 5) {
case 0:
stud.matrnr = atol(wort);
break;
case 1:
strcpy(stud.name, wort);
break;
case 2:
strcpy(stud.vorname, wort);
break;
case 3:
strcpy(stud.datum,wort);
break;
case 4:
stud.note = atof(wort);
break;
}
wordCounter++;
i = 0;
continue;
}
if (wordCounter % 5 == 0 && (char)cnr != ';') {
wort[i] = (char)cnr;
i++;
//stud.matrnr = atol(wort);
}
if (wordCounter % 5 == 1) {
wort[i] = (char)cnr;
i++;
//strcpy(stud.name, wort);
}
if (wordCounter % 5 == 2) {
wort[i] = (char)cnr;
i++;
//strcpy(stud.vorname, wort);
}
if (wordCounter % 5 == 3) {
wort[i] = (char)cnr;
i++;
//strcpy(stud.datum,wort);
}
if (wordCounter % 5 == 4) {
wort[i] = (char)cnr;
i++;
//stud.note = atof(wort);
}
}
fclose (pFile);
}
for (int i(0) ; i <= studentCounter; i++) {
cout <<mystud[i].matrnr << " " << mystud[i].name << " " << mystud[i].vorname <<" "
<< mystud[i].datum <<" " << mystud[i].note << endl;
//printf("%5ld %5s %5s %5s %5f \n",mystud[i].matrnr,mystud[i].name,mystud[i].vorname,mystud[i].datum,mystud[i].note);
}
return 0;
}
I am not sure if it has to do with a wrong increment variables, or the fact that I don't put an '\0' at the end of my wort[] array..and therefore not recognizing the end of my array? And if so, how do I do it without knowing where the end exactly is... ? (I don't know the length of the words..)
EDIT: I updated my code again, the only thing that wonders me is that the LAST LINE IS NOT BEING CORRECTLY PARSED , its showing some rubbish, and I can't see the error in my code...
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;Bau;Maschine;02.02.2010;2.3;
Suggestion: use a case structure for the parsing, and make yourself a "copyToSemicolon" function: then you can write things like
sIndexCount = 0;
char temp[50];
while((cnr=fgetc(pFile)) != EOF) {
offset = 0;
for(var = 0; var < 5; var++ {
switch(var) {
case 0:
offset = copyToSemicolon(temp, cnr, offset) + 1;
stud.matrnr = atoi(temp);
break;
case 1:
offset = copyToSemicolon(mystud[sIndexCount].vorname, cnr, offset) + 1;
break;
... etc
}
}
sIndexCount++;
if(sIndexCount == 50) break; // in case the input file is longer than our structure
}
And you need a function copyToSemicolon that takes two char* pointers as inputs, and that copies characters from the second string (starting at offset) until it reaches either a semicolon or the end of line - and that returns the offset it reached (last character read).
int copyToSemicolon(char* dest, char* source, int offset) {
while(source[offset] != ';' && source[offset] != '\n') {
*dest = source[offset++];
dest++;
}
return offset;
}
EDIT strtok method:
sIndexCount = 0;
char temp[50];
while((cnr=fgetc(pFile)) != EOF) {
offset = 0;
temp = strtok(cnr, ';');
for(var = 0; var < 5; var++ {
switch(var) {
case 0:
stud.matrnr = atoi(temp);
break;
case 1:
strcpy(mystud[sIndexCount].vorname, strtok(NULL, ';'));
break;
... etc
case 4:
mystud[sIndexCount].note = atof(strtok(NULL, '\n'));
}
}
sIndexCount++;
if(sIndexCount == 50) break; // in case the input file is longer than our structure
}
One issue that I am seeing is that your code copies or parses one character at a time, such that when you're reading 2345678;Meier;Hans;12.10.1985;2.4; you first set stud.matrnr to 2, then 23, then 234, then 2345, then 23456, then 234567, then 2345678. Similarly, for stud.name, you first set it to M, then the Me, then to Mei, etc. I propose to you to think of things in a different way. I'll give you some pseudocode:
while (!eof) {
get character from file
if (character isn't ';' and isn't '\n') {
copy character into buffer (increment buffer index)
} else if (character is ';') {
it's the end of a word. Put it in its place - turn it to an int, copy it, whatever
reset the buffer
} else if (character is '\n') {
it's the end of the last word, and the end of the line. Handle the last word
reset the buffer
copy the structure
}
}
This should make life a lot easier on you. You're not changing your data nearly as much, and if you need to debug, you can focus on each part on its own.
Generally, in programming, the first step is making sure you can say in your native speaking language what you want to do, then it's easier to translate it to code. You're close with you implementation, and you can make it work. Just be sure you can explain what should be happening when you see ';' or '\n'.
Since you have tagged this as C++, you should consider using std::getline for reading the line from the file, the use std::getline(file, text_before_semicolon, ';') for parsing the fields.
You could also use std::istringstream for converting the textual representation in the text line to internal numeric format.