please teach me how to get rid of those if statements by using functors (or any other better methods) inside the following loop:
//Loop over each atom
std::string temp_name ;
float dst;
for (pdb::pdb_vector:: size_type i=0; i < data.size(); ++i)
{
if (type == 0)
{
//choose by residue name
temp_name = data[i].residue_name;
} else {
//choose by atom name
temp_name = data[i].atom_name;
}
//compare the name and extract position if matched
if (temp_name.compare(name) == 0)
{
if (direction.compare("x") == 0)
{
dst = ::atof(data[i].x_coord.c_str());
} else if ((direction.compare("y") == 0)) {
dst = ::atof(data[i].y_coord.c_str());
} else {
dst = ::atof(data[i].z_coord.c_str());
}
}
}
you can replace if(type == 0) with the ternary operator:
// if(type == 0) ...
temp_name = (type == 0 ? data[i].residue_name : data[i].atom_name);
but the rest of your checks seem like they would only be less readable if you tried something similar.
Related
I'm currently doing an assignment that requires us to create our own library for string comparison without using compare(), etc.
I got it to work, but during my research I created a bool function for character compare and return values.
It needs to work as if it returns like compare(), where 0 = strings are equal and 0 > or 0 < for not equal instead of true or false like I currently set it up to be.
I tried to change the bool functions to int but now when I run the program that was correctly returning strings are equal, it's showing not equal.
Header code:
bool compare_char(char &c1, char &c2)
{
if (c1 == c2)
return true;
else if (toupper(c1) == toupper(c2))
return true;
else
return false;
}
bool insensitive_string_comparision(string &string_one, string &string_two)
{
return ((string_one.size() == string_two.size()) &&
equal(string_one.begin(), string_one.end(), string_two.begin(), &compare_char));
}
string remove_spaces(string string)
{
string.erase(remove(string.begin(), string.end(), ' '), string.end());
return string;
}
string remove_punctuation(string string)
{
for (size_t i = 0, len = string.size(); i < len; ++i)
{
if (ispunct(string[i]))
{
string.erase(i--, 1);
len = string.size();
}
}
return string;
Int header changes
int compare_char(char &c1, char &c2)
{
if (c1 == c2)
return 0;
else if (toupper(c1) == toupper(c2))
return 0;
else if (toupper(c1) > toupper(c2))
return -1;
else if (toupper(c1) < toupper(c2))
return 1;
}
int insensitive_string_comparision(string &string_one, string &string_two)
{
return ((string_one.size() == string_two.size()) &&
equal(string_one.begin(), string_one.end(), string_two.begin(), &compare_char));
}
Int main changes
int result = insensitive_string_comparision(string_one, string_two);
if (result == 0)
cout << "Both Strings are equal." << endl;
else (result == 1 || result == -1)
cout << "Both Strings are not equal." << endl;
return 0;
I feel like I'm going to have to redesign the entire function to return the value that is similar to compare().
I'm assuming bool was the wrong decision to begin with? Where should I go moving forward to return a correct value?
In your question you are not entirely clear about how you want to compare the strings, but I made some assumptions based on your example code. You can fix your problem by writing insensitive_string_comparision like:
int insensitive_string_comparision(string &string_one, string &string_two) {
int len_one = string_one.length();
int len_two = string_two.length();
int len_comparison = 0;
if (len_one > len_two) {
len_comparison = -1;
} else if (len_one < len_two) {
len_comparison = 1;
}
int minlen = (len_comparison == -1) ? len_one : len_two;
for (int i = 0; i < minlen; i++) {
int order = compare_char(string_one[i], string_two[i]);
if (order != 0) {
return order;
}
}
return len_comparison;
}
I'd also recommend turning on warnings on your compiler. You don't need to put some of your return statements in else blocks.
This must have a canonical answer but I cannot find it... Using a regular expression to validate an email address has answers which show regex is really not the best way to validate emails. Searching online keeps turning up lots and lots of regex-based answers.
That question is about PHP and an answer references a handy class MailAddress. C# has something very similar but what about plain old C++? Is there a boost/C++11 utility to take all the pain away? Or something in WinAPI/MFC, even?
I have to write one solution because I have a g++ version installed that doesnt support std::regex (Application crashes) and I dont want to upgrade the thing for a single E-Mail validation as this application probably never will need any further regex I wrote a function doing the job. You can even easily scale allowed characters for each part of the E-Mail addres (before #, after # and after '.') depdending on your needs. Took 20 min to write and was way easier then messing with compiler and environment stuff just for one function call.
Here you go, have fun:
bool emailAddressIsValid(std::string _email)
{
bool retVal = false;
//Tolower cast
std::transform(_email.begin(), _email.end(), _email.begin(), ::tolower);
//Edit these to change valid characters you want to be supported to be valid. You can edit it for each section. Remember to edit the array size in the for-loops below.
const char* validCharsName = "abcdefghijklmnopqrstuvwxyz0123456789.%+_-"; //length = 41, change in loop
const char* validCharsDomain = "abcdefghijklmnopqrstuvwxyz0123456789.-"; //length = 38, changein loop
const char* validCharsTld = "abcdefghijklmnopqrstuvwxyz"; //length = 26, change in loop
bool invalidCharacterFound = false;
bool atFound = false;
bool dotAfterAtFound = false;
uint16_t letterCountBeforeAt = 0;
uint16_t letterCountAfterAt = 0;
uint16_t letterCountAfterDot = 0;
for (uint16_t i = 0; i < _email.length(); i++) {
char currentLetter = _email[i];
//Found first #? Lets mark that and continue
if (atFound == false && dotAfterAtFound == false && currentLetter == '#') {
atFound = true;
continue;
}
//Found '.' after #? lets mark that and continue
if (atFound == true && dotAfterAtFound == false && currentLetter == '.') {
dotAfterAtFound = true;
continue;
}
//Count characters before # (must be > 0)
if (atFound == false && dotAfterAtFound == false) {
letterCountBeforeAt++;
}
//Count characters after # (must be > 0)
if (atFound == true && dotAfterAtFound == false) {
letterCountAfterAt++;
}
//Count characters after '.'(dot) after # (must be between 2 and 6 characters (.tld)
if (atFound == true && dotAfterAtFound == true) {
letterCountAfterDot++;
}
//Validate characters, before '#'
if (atFound == false && dotAfterAtFound == false) {
bool isValidCharacter = false;
for (uint16_t j = 0; j < 41; j++) {
if (validCharsName[j] == currentLetter) {
isValidCharacter = true;
break;
}
}
if (isValidCharacter == false) {
invalidCharacterFound = true;
break;
}
}
//Validate characters, after '#', before '.' (dot)
if (atFound == true && dotAfterAtFound == false) {
bool isValidCharacter = false;
for (uint16_t k = 0; k < 38; k++) {
if (validCharsDomain[k] == currentLetter) {
isValidCharacter = true;
break;
}
}
if (isValidCharacter == false) {
invalidCharacterFound = true;
break;
}
}
//After '.' (dot), and after '#' (.tld)
if (atFound == true && dotAfterAtFound == true) {
bool isValidCharacter = false;
for (uint16_t m = 0; m < 26; m++) {
if (validCharsTld[m] == currentLetter) {
isValidCharacter = true;
break;
}
}
if (isValidCharacter == false) {
invalidCharacterFound = true;
break;
}
}
//Break the loop to speed up thigns if one character was invalid
if (invalidCharacterFound == true) {
break;
}
}
//Compare collected information and finalize validation. If all matches: retVal -> true!
if (atFound == true && dotAfterAtFound == true && invalidCharacterFound == false && letterCountBeforeAt >= 1 && letterCountAfterAt >= 1 && letterCountAfterDot >= 2 && letterCountAfterDot <= 6) {
retVal = true;
}
return retVal;
}
In my game I keep track of unlocked levels with a vector std::vector<bool> lvlUnlocked_;.
The simple function to save the progress is this:
void save() {
std::stringstream ss;
std::string stringToSave = "";
std::ofstream ofile("./progress.txt");
if (ofile.good()) {
ofile.clear();
for (std::size_t i = 0; i < levelUnlocked_.size(); ++i) {
ss << "lvl" << i << "=" << (lvlUnlocked_.at(i) ? "1" : "0") << std::endl;
}
stringToSave = ss.str();
ofile << stringToSave;
ofile.close();
}
}
This works and is nice since I can just use a loop to dump the info.
Now to the part where I am stuck, the lower part of my load function (see comment in code below):
void load() {
std::ifstream ifile("./progress.txt");
if (ifile.good()) {
int begin;
int end;
std::string line;
std::string stringKey = "";
std::string stringValue = "";
unsigned int result;
while (std::getline(ifile, line)) {
stringKey = "";
stringValue = "";
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
for (int i = 0; i < begin - 1; i++) {
stringKey += line.at(i);
}
for (int i = begin; i < end; i++) {
stringValue += line.at(i);
}
result = static_cast<unsigned int>(std::stoi(stringValue));
// usually I now compare the value and act accordingly, like so:
if (std::strcmp(stringKey.c_str(), "lvl0") == 0) {
lvlUnlocked_.at(0) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl1") == 0) {
lvlUnlocked_.at(1) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl2") == 0) {
lvlUnlocked_.at(2) = true;
}
// etc....
}
}
}
This works fine, but...
the problem is that I have 100+ levels and I want it to be dynamic based on the size of my lvlUnlocked_ vector instead of having to type it all like in the code above.
Is there a way to somehow make use of a loop like in my save function to check all levels?
If you parse your key to extract a suitable integer value, you can just index into the bit-vector with that:
while (std::getline(ifile, line)) {
const size_t eq = line.find('=');
if (eq == std::string::npos)
// no equals sign
continue;
auto stringKey = line.substr(0, eq);
auto stringValue = line.substr(eq+1);
if (stringKey.substr(0,3) != "lvl")
// doesn't begin with lvl
continue;
// strip off "lvl"
stringKey = stringKey.substr(3);
size_t end;
std::vector<bool>::size_type index = std::stoi(stringKey, &end);
if (end == 0 || end != stringKey.length())
// not a valid level number
continue;
if (index >= lvlUnlocked_.size())
// out of range
continue;
// Set it :-)
lvlUnlocked_[index] = stringValue=="1";
}
(I've also updated your parsing for "key=value" strings to more idiomatic C++.)
So I am debugging a runtime error I am getting. "string subscript out of range".
I know where the problem is and what is causing it, yet I am looking for a possible solution that will perform in a similar or identical manner without giving me the error.
Here is the code snippet to where the error occurs. Correct me if I am wrong, the problem is occurring because I am declaring a 0 length string then trying to manipulate an nth element.
std::string VsuShapeLine::GetRunwayNumber()
{
std::string name, nbstr, newnbstr, convnbstr;
int idx,idx2, num, count, pos;
char buf[3];
int idx3=-1;
name = this->GetName();
idx = name.find("ALight");
if (idx == -1)
{
idx = name.find("Lights");
idx3 = name.find_last_of("Lights");
}
idx2 = name.find('_');
idx2 +=3;
nbstr = name.substr(idx2, idx-idx2);
if (idx3 != -1)
idx3++;
else
idx3 = idx+6;
if (name.at(idx3) == 'N')
{
pos = nbstr.length();
if (isalpha(nbstr[idx-1]))
nbstr[pos-1] = _toupper(nbstr[pos-1]);
return (nbstr);
}
else if (name.at(idx3) == 'F')
{
convnbstr = nbstr.substr(0,2);
num = atoi(convnbstr.data());
num +=18;
_itoa(num, buf, 10);
newnbstr = buf;
count = nbstr.size();
if (count > 2)
{
if (nbstr.at(2) == 'l' || nbstr.at(2) == 'L')
newnbstr += 'r';
else if (nbstr.at(2) == 'r'|| nbstr.at(2) == 'R')
newnbstr += 'l';
else if (nbstr.at(2) == 'c' || nbstr.at(2) == 'C')
newnbstr += 'c';
}
pos = newnbstr.length();
if (isalpha(newnbstr[pos-1]))
newnbstr[pos-1] = _toupper(newnbstr[pos-1]);
return (newnbstr);
}
return ("");
}
Btw for whoever is interested the problem was at this line:
if (isalpha(nbstr[idx-1])
At this point nbstr is a string of length 3 and idx' value, the way my program works, is always either 9 or 10.
Also as Retired Ninja mentioned checks should be done after using the string::find function.
I am looking for a C++ class I can incorporate into a project I am working on.
the functionality I need is evaluation of string operations to numerical form: for example "2 + 3*7" should evaluate to 23.
I do realize what I am asking is a kind of an interpreter, and that there are tools to build them, by my background in CS is very poor so I would appreciate if you can point me to a ready made class .
This should do exactly what you want. You can test it live at: http://www.wowpanda.net/calc
It uses Reverse Polish Notation and supports:
Operator precedence (5 + 5 * 5 = 30 not 50)
Parens ((5 + 5) * 5 = 50)
The following operators: +, -, *, /
EDIT: you'll probably want to remove the Abs() at the bottom; for my needs 0 - 5 should be 5 and not -5!
static bool Rpn(const string expression, vector<string> &output)
{
output.clear();
char *end;
vector<string> operator_stack;
bool expecting_operator = false;
for (const char *ptr = expression.c_str(); *ptr; ++ptr) {
if (IsSpace(*ptr))
continue;
/* Is it a number? */
if (!expecting_operator) {
double number = strtod(ptr, &end);
if (end != ptr) {
/* Okay, it's a number */
output.push_back(boost::lexical_cast<string>(number));
ptr = end - 1;
expecting_operator = true;
continue;
}
}
if (*ptr == '(') {
operator_stack.push_back("(");
expecting_operator = false;
continue;
}
if (*ptr == ')') {
while (operator_stack.size() && operator_stack.back() != "(") {
output.push_back(operator_stack.back());
operator_stack.pop_back();
}
if (!operator_stack.size())
return false; /* Mismatched parenthesis */
expecting_operator = true;
operator_stack.pop_back(); /* Pop '(' */
continue;
}
if (*ptr == '+' || *ptr == '-') {
while (operator_stack.size() && IsMathOperator(operator_stack.back())) {
output.push_back(operator_stack.back());
operator_stack.pop_back();
}
operator_stack.push_back(boost::lexical_cast<string>(*ptr));
expecting_operator = false;
continue;
}
if (*ptr == '*' || *ptr == '/') {
while (operator_stack.size() && (operator_stack.back() == "*" || operator_stack.back() == "/")) {
output.push_back(operator_stack.back());
operator_stack.pop_back();
}
operator_stack.push_back(boost::lexical_cast<string>(*ptr));
expecting_operator = false;
continue;
}
/* Error */
return false;
}
while (operator_stack.size()) {
if (!IsMathOperator(operator_stack.back()))
return false;
output.push_back(operator_stack.back());
operator_stack.pop_back();
}
return true;
} // Rpn
/***************************************************************************************/
bool Calc(const string expression, double &output)
{
vector<string> rpn;
if (!Rpn(expression, rpn))
return false;
vector<double> tmp;
for (size_t i = 0; i < rpn.size(); ++i) {
if (IsMathOperator(rpn[i])) {
if (tmp.size() < 2)
return false;
double two = tmp.back();
tmp.pop_back();
double one = tmp.back();
tmp.pop_back();
double result;
switch (rpn[i][0]) {
case '*':
result = one * two;
break;
case '/':
result = one / two;
break;
case '+':
result = one + two;
break;
case '-':
result = one - two;
break;
default:
return false;
}
tmp.push_back(result);
continue;
}
tmp.push_back(atof(rpn[i].c_str()));
continue;
}
if (tmp.size() != 1)
return false;
output = Abs(tmp.back());
return true;
} // Calc
/***************************************************************************************/
boost::spirit comes with a calculator example which would do what you need:
http://www.boost.org/doc/libs/1_33_1/libs/spirit/example/fundamental/ast_calc.cpp
muParser is written in C++ and does just what you need.
C++ in Action, in addition to being a great book on C++, includes a fully working calculator, doing what you need (and actually much more). And the book is available for free online