Recursive comparison of two strings - c++

The function int compare(...), checks if 2 strings are equal ignoring case and any non-alphabetical characters, e.g. "a?...!b" is equivalent to "ab". Returns 1 if equal, 0 else. However, there's a bug in my code!
int compare(const char* string1, const char* string2)
{
if(string1 == NULL || string2 == NULL)
return 0;
std::cout << *string1 << " | " << *string2 << std::endl;
if((!isalpha(*string1) && *string1 != ' ') && (!isalpha(*string2) && *string2 != ' '))
{
compare(++string1,++string2);
}
else if(!isalpha(*string1) && *string1 != ' ')
{
compare(++string1,string2);
}
else if(!isalpha(*string2) && *string2 != ' ')
{
compare(string1, ++string2);
}
if(tolower(*string1) != tolower(*string2))
return 0;
if(*string1 == '\0')
return 1;
if(*string1 == *string2)
compare(++string1, ++string2);
}
If I try and run this code with for example:
compare("a !!!b", "a b");
The output really confuses me:
a | b
|
! |
! |
! |
b | b
^#| ^#
| a
^#| ^#
| a
It returns 0 (not equal). It doesn't stop running once it gets to b | b, why?

Besides needing the return statement you have a flaw in your logic. You need to check if both strings are empty and thus equal earlier in the function:
int compare(const char* string1, const char* string2)
{
if(string1 == NULL || string2 == NULL)
return 0;
// This needs to go here
if(*string1 == '\0' && *string2 == '\0') {
return 1;
}
std::cout << *string1 << " | " << *string2 << std::endl;
if((!isalpha(*string1) && *string1 != ' ') && (!isalpha(*string2) && *string2 != ' '))
{
return compare(++string1,++string2);
}
else if(!isalpha(*string1) && *string1 != ' ')
{
return compare(++string1,string2);
}
else if(!isalpha(*string2) && *string2 != ' ')
{
return compare(string1, ++string2);
}
if(tolower(*string1) != tolower(*string2))
return 0;
if(*string1 == *string2)
return compare(++string1, ++string2);
}
You can check it here: https://ideone.com/Si78Nz

Related

c++ multiple regex extractions to an array from dbc entry [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 10 days ago.
Improve this question
Hello I would like to extract the parameters from the following string:
VAL_ 234 State1 123 "Description 1" 0 "Description 2 with \n new line" 90903489 "Big value and special characters &$§())!" ;
The desired matches are
234
State1
and then an array with unsigned integer and string combination
123 "Description 1"
0 "Description 2 with \n new line"
90903489 "Big value and special characters &$§())!"
The array shall be split in a second step if it is not possible to do it directly.
With the following regex I just get always the last match of the array 90903489 "Big value and special characters &$§())!"
^VAL_ ([0-9]+) ([A-Za-z_][A-Za-z_0-9]*) ([0-9]*\\s\"[^\"]*\"\\s)+
Is there a possibility to extract the values?
I found already
auto blah = std::string{"5001 | 5002 | 5003"};
auto values = std::vector<std::string>{
std::sregex_token_iterator{blah.begin(), blah.end(), std::regex{R"(\d+)"}},
std::sregex_token_iterator{}};
from this post but it returns me just the complete string. Is there a possibility to iterate over the submatches?
Not sure if you have any specific requirements on how the matches need to be separated, but you can match either of the patterns with the following regular expression:
(?:^VAL_\s(\d+)\s(\w+)|\s(\d+\s".+?"))
Sample code:
const std::string input{ R"(VAL_ 234 State1 123 "Description 1" 0 "Description 2 with \n new line" 90903489 "Big value and special
characters &$§())!")" };
const std::regex regex{ R"((?:^VAL_\s(\d+)\s(\w+)|\s(\d+\s".+?")))" };
const std::sregex_iterator end{};
for(auto it = std::sregex_iterator{ std::cbegin(input), std::cend(input), regex };
it != end; ++it) {
auto match = *it;
if (match.empty()) {
std::cerr << "Nothing matched" << '\n';
continue;
} else {
if (match[1].matched) {
std::cout << "Val match: " << match[1].str() << '\n';
}
if (match[2].matched) {
std::cout << "State match: " << match[2].str() << '\n';
}
if (match[3].matched) {
std::cout << "Etc match: " << match[3].str() << '\n';
}
}
}
Based on #rustyx link I created my own parser
enum VALToken {
Identifier = 0,
CANId,
SignalName,
Value,
Description
};
struct ValueDescription{
std::string value;
std::string description;
};
int main(int argc, char *argv[])
{
const std::string s = R"(VAL_ 234 State1 123 "Description 1" 0 "Description 2 with \n new line" 90903489 "Big value and special characters &$§())!" ;)";
auto state = Identifier;
const char* a = s.data();
std::string can_id;
std::string signal_name;
std::vector<ValueDescription> vds;
ValueDescription vd;
for (;;) {
switch (state) {
case Identifier: {
if (*a != 'V')
return 0;
a++;
if (*a != 'A')
return 0;
a++;
if (*a != 'L')
return 0;
a++;
if (*a != '_')
return 0;
a++;
if (*a != ' ')
return 0;
a++; // skip whitespace
state = CANId;
break;
}
case CANId: {
while(*a >= '0' && *a <= '9') {
can_id += *a;
a++;
}
if (can_id.empty())
return 0;
if (*a != ' ')
return 0;
a++; // skip whitespace
state = SignalName;
break;
}
case SignalName: {
if ((*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z') || *a == '_')
signal_name += *a;
else
return 0;
a++;
while ((*a >= 'a' && *a <= 'z') || (*a >= 'A' && *a <= 'Z') || *a == '_' || (*a >= '0' && *a <= '9')) {
signal_name += *a;
a++;
}
if (*a != ' ')
return 0;
a++; // skip whitespace
state = Value;
break;
}
case Value: {
std::string value_str;
while (*a >= '0' && *a <= '9') {
value_str += *a;
a++;
}
if (value_str.empty())
return 0;
if (*a != ' ')
return 0;
a++; // skip whitespace
vd.value = value_str;
state = Description;
break;
}
case Description: {
std::string desc;
if (*a != '"')
return 0;
a++;
while (*a != '"' && *a != 0) {
desc += *a;
a++;
}
if (*a == 0)
return 0;
a++;
if (*a != ' ')
return 0;
a++; // skip whitespace
vd.description = desc;
vds.push_back(vd);
state = Value;
break;
}
}
}
return 0;
}
I would do a regex_match followed by a loop using an sregex_iterator.
[Demo]
#include <fmt/core.h>
#include <regex>
#include <string>
int main() {
const std::string text{ "VAL_ 234 State1"
" 123 \"Description 1\""
" 0 \"Description 2 with \\n new line\""
" 90903489 \"Big value and special characters &$§())!\""
};
const std::regex pattern{ R"(VAL_ (\d+) \w+(\d+)(.*))" };
std::smatch matches{};
if (std::regex_match(text, matches, pattern)) {
fmt::print("{}\n{}\n", matches[1].str(), matches[2].str());
std::regex array_pattern{ R"(\s+(\d+)\s+\"([^"]+)\")" };
auto array_text{ matches[3].str() };
for (std::sregex_iterator it{ array_text.begin(), array_text.end(), array_pattern };
it != std::sregex_iterator{};
++it) {
std::smatch array_matches{ *it };
fmt::print("\t'{}', '{}'\n", array_matches[1].str(), array_matches[2].str());
}
}
}
// Outputs:
//
// 234
// 1
// '123', 'Description 1'
// '0', 'Description 2 with \n new line'
// '90903489', 'Big value and special characters &$§())!'

Checking balanced parantheses code is not behaving as per expectation

I am solving a question in which I have to check if the input string of parentheses are balanced or not,
and if not, code is expected to return the 1-based index of unmatched closing parenthesis, and if not found, return the 1-based index of the opening parenthesis. My code runs fine if I implement only the parenthesis checking part, but as I try to implement the returning index part, the code starts giving 'success' output for all the input.
Here is the code:
#include<iostream>
#include<string>
#include<algorithm>
#include<stack>
using namespace std;
int process_input( string value );
bool closing_bracket_match(char opening_bracket, char closing_bracket);
bool closing_bracket_match(char opening_bracket , char closing_bracket){
if( (opening_bracket == '{' && closing_bracket == '}') || (opening_bracket == '(' && closing_bracket == ')') || (opening_bracket == '[' &&
closing_bracket == ']') ){
return true;
}
else{
return false;
}
}
int process_input( string value ){
stack<char> processed_input{};
int unmatched_index{};
for( size_t i{}; i< value.size() ; ++i ){
if( value.at(i) == '{' || value.at(i) == '(' || value.at(i) == '[' ){ // check for opening brackets
processed_input.push(value.at(i)); // Appending opening bracket into the stack
}
else if( (value.at(i) == '}' || value.at(i) == ')' || value.at(i) == ']') && (processed_input.empty() == false) &&
closing_bracket_match(processed_input.top(),value.at(i)) ){ // the bracket in stack would be popped
processed_input.pop(); // matching brackets ar removed
}
}
if( processed_input.empty()==true ){
return 0;
}//This part is causing the bug
if(processed_input.empty() == false){
auto it = find( value.begin(), value.end(), processed_input.top() );
if( it!= value.end() ){
unmatched_index = distance(value.begin() , it)+1; //returning the 1 -based index of unmatched bracket
}
return unmatched_index;
}
}
int main(){
string input{};
cout<<"Please enter the code here: "; // debug line
cin>> input;
int result{};
result = process_input(input);
if( result == 0 ){
cout<<"Success";
}
else{
cout<<result;
}
}
If you want to return a position of the last (innermost) unmatched paren, you need to store it together with its position on the stack. Seeking for it leads to errors.
Which of potentially several items equal to the one you seek will find() find?
For example, in "(((" there are three unmatched opening parentheses, and all of them are equal to '('. Which one do you want to return as a result? Which one do you actually return?
And how about this input: "()("...?
Added
Here is a possible solution. Please note how it does not find() anything, but it stores on a stack all information necessary to produce the desired output.
#include<iostream>
#include<string>
#include<stack>
using std::string;
using std::stack;
bool is_opening(char c) {
return c == '(' || c == '[' || c == '{';
}
bool is_closing(char c) {
return c == ')' || c == ']' || c == '}';
}
bool is_matching(char opn, char cls) {
switch(opn) {
case '(': return cls == ')';
case '[': return cls == ']';
case '{': return cls == '}';
}
return false;
}
int process_input( string value )
{
stack<char> opn_parens{};
stack<size_t> positions{};
for( size_t i{}; i < value.size() ; ++i )
{
const char ch = value.at(i);
if( is_opening(ch) )
{
opn_parens.push(ch);
positions.push(i);
}
else if( is_closing(ch) )
{
if( opn_parens.empty() ) // a closing paren with no unmatched opening one
return i + 1;
const char opn_ch = opn_parens.top();
const size_t opn_pos = positions.top();
if( ! is_matching(opn_ch, ch) ) // unmatched closing paren
return opn_pos + 1;
opn_parens.pop(); // remove a matched paren
positions.pop();
}
}
if( ! positions.empty() ) // some unmatched parens remain
return positions.top() + 1;
return 0;
}
int main(){
std::cout << process_input("hello(mum[]{(dad()[bro!])})") << std::endl;
std::cout << process_input("))") << std::endl;
std::cout << process_input("([") << std::endl;
std::cout << process_input("([)") << std::endl;
std::cout << process_input("([{") << std::endl;
}
You can see it working at https://godbolt.org/z/e8fYW5fKz

How figlet fit and smush?

I am creating a figlet like code in c++ and i am currently doing fiting by inserting null at left side character and find min space and remove minspace and null the character,( for understanding take null as '0' )
" __0 "
"| _|0 "
"| |0 _____ "
"| |0 |_____|"
"| |0 $ "
"|__|0 "
(if any space line i insert null at start) Now here min space is 3 so i remove 3 space and null in that and this code works perfect and smushing by inheriting the fitting class and i will pass the right side char by inserting null like
" 0"
" 0"
" _0____ "
"|0_____|"
" $0 "
" 0"
it will give result like
" __ 0"
"| _| 0"
"| | _0____ "
"| ||0_____|"
"| | $0 "
"|__| 0"
Now i will store pos of null and remove it, In next loop check the two character before the null, if any one are HardBlank then i return the function else i smush it in next loop, but above are not smush( not work correctly ) due to HardBlank, so i want to know how figlet actually smush i downloaded the figlet code from here but i did not understand the code.
There is any better algorithm than this or How figlet actually do fitting and smushing ?
All suggestions are welcome,
Thanks in advance.
I asked this question long time ago now, But I answering this question now for future readers I have written algorithm a better than this some time ago that do the following,
Kerning or fitting :
The main part of this thing is trim, so lets create an function that takes two input that figs is left side FIGchar and figc is right side FIGchar. The first thing to do is find the number of space that need to be removed from right side of figs and left side of figc, we can easily find this by counting total space in right size of figs and left side of figc. Finally take minimum of that that is the space count that has to be removed here is that implementation,
/**
* #brief trims in a deep
*
* #param figs fig string
* #param figc fig character
*/
void trim_deep(Figs_type &figs, Figc_type &figc) const
{
std::vector<size_type> elem;
for (size_type i = 0; i < figs.size(); ++i)
{
int lcount = 0, rcount = 0;
for (auto itr = figs[i].rbegin(); itr != figs[i].rend(); ++itr)
{
if (*itr == ' ')
++lcount;
else
break;
}
for (auto itr = figc[i].begin(); itr != figc[i].end(); ++itr)
{
if (*itr == ' ')
++rcount;
else
break;
}
elem.push_back(lcount + rcount);
}
size_type space = *std::min_element(elem.begin(), elem.end());
for (size_type i = 0; i < figs.size(); ++i)
{
size_type siz = space;
while (siz > 0 && figs[i].back() == ' ')
{
figs[i].pop_back();
--siz;
}
figc[i].erase(0, siz);
}
}
Smushing:
This smushing can be done easily by using above function with only smush right most character of figs and left side character of figc if it is smushble here is implementation,
/**
* #brief smush rules
* #param lc left character
* #param rc right character
* #return smushed character
*/
char_type smush_rules(char_type lc, char_type rc) const
{
//()
if (lc == ' ')
{
return rc;
}
if (rc == ' ')
{
return lc;
}
//(Equal character smush)
if (lc == rc)
{
return rc;
}
//(Underscores smush)
if (lc == '_' && this->cvt("|/\\[]{}()<>").find(rc) != string_type::npos)
{
return rc;
}
if (rc == '_' && this->cvt("|/\\[]{}()<>").find(lc) != string_type::npos)
{
return lc;
}
//(Hierarchy Smushing)
auto find_class = [](char_type ch) -> size_type
{
if (ch == '|')
{
return 1;
}
if (ch == '/' || ch == '\\')
{
return 3;
}
if (ch == '[' || ch == ']')
{
return 4;
}
if (ch == '{' || ch == '}')
{
return 5;
}
if (ch == '(' || ch == ')')
{
return 6;
}
return 0;
};
size_type c_lc = find_class(lc);
size_type c_rc = find_class(rc);
if (c_lc > c_rc)
{
return lc;
}
if (c_rc > c_lc)
{
return rc;
}
//(Opposite smush)
if (lc == '[' && rc == ']')
{
return '|';
}
if (lc == ']' && rc == '[')
{
return '|';
}
if (lc == '{' && rc == '}')
{
return '|';
}
if (lc == '}' && rc == '{')
{
return '|';
}
if (lc == '(' && rc == ')')
{
return '|';
}
if (lc == ')' && rc == '(')
{
return '|';
}
//(Big X smush)
if (lc == '/' && rc == '\\')
{
return '|';
}
if (lc == '\\' && rc == '/')
{
return 'Y';
}
if (lc == '>' && rc == '<')
{
return 'X';
}
//(universel smush)
return lc;
}
/**
* #brief smush algoriths on kerned Fig string and character
*
* #param figs
* #param figc
*/
void smush(Figs_type &figs, Figc_type figc, char_type hb) const
{
bool smushble = true;
for (size_type i = 0; i < figs.size(); ++i)
{
if (figs[i].size() == 0 || figc[i].size() == 0)
{
smushble = false;
}
else if ((figs[i].back() == hb) && !(figc[i].front() == hb))
{
smushble = false;
}
}
if (smushble)
{
for (size_type i = 0; i < figs.size(); ++i)
{
char_type val = smush_rules(figs[i].back(), figc[i].front());
figs[i].pop_back();
figc[i].erase(0, 1);
figs[i] += string_type(1, val) + figc[i];
}
}
else
{
for (size_type i = 0; i < figs.size(); ++i)
{
figs[i] += figc[i];
}
}
}
This code is directly copied from this file, So the types can be confusing here is overview Figs_type and Figc_type are just like vector of string and other type are reflects in their name and the repo can be found here.

Removing all but one whitespace between words in C++

I need to remove all but one white space between the words. I go through the string and if (temp.back() == ' ' && c != ' ') I check for the last space before we come onto the next word. But it removes all of the white spaces. Any hint where the problem is?
string removeWhiteSpace(string current)
{
string myNewString = "";
string temp = "";
for (char c : current)
{
temp.push_back(c);
if (temp.back() == ' ' && c != ' ')
{
myNewString.push_back(' ');
}
if (c != ' ')
{
myNewString.push_back(c);
}
}
return myNewString;
}
The problem is in the conditional
if (temp.back() == ' ' && c != ' ')
you want to add the space if last character is NOT a space and c is a space:
if (temp.back() != ' ' && c == ' ')
(you reversed == and != operators).
Also you need to push the new character c AFTER this conditional block (otherwise temp.back() and c will always be the same character).
Finally at the beginning the string temp is empty, calling back() is not allowed, you should initialize it with a non-blank instead (e.g. temp = "x").
The final function that works is therefore:
string removeWhiteSpace(string current)
{
string myNewString = "";
string temp = "x";
for (char c : current)
{
if (temp.back() != ' ' && c == ' ')
{
myNewString.push_back(' ');
}
temp.push_back(c);
if (c != ' ')
{
myNewString.push_back(c);
}
}
return myNewString;
}
You possibly want to remove extra whitespaces. This code will help.
string removeWhiteSpace(string current)
{
string myNewString = "";
string temp = "";
int l=current.length();
myNewString+=current[0];
for(int i=1;i<l;i++){
if(myNewString[myNewString.length()-1]==' ' && current[i]==' ')
continue;
else
myNewString+=current[i];
}
return myNewString;
}
A more C++ish solution:
#include <algorithm>
#include <cctype>
#include <string>
#include <utility>
#include <iostream>
std::string remove_excessive_ws(std::string str)
{
bool seen_space = false;
auto end{ std::remove_if(str.begin(), str.end(),
[&seen_space](unsigned ch) {
bool is_space = std::isspace(ch);
std::swap(seen_space, is_space);
return seen_space && is_space;
}
)
};
if (end != str.begin() && std::isspace(static_cast<unsigned>(end[-1])))
--end;
str.erase(end, str.end());
return str;
}
int main()
{
char const *foo{ "Hello World! " };
std::cout << '\"' << remove_excessive_ws(foo) << "\"\n";
}
Output:
"Hello World!"

Parsing Parenthesis using stack template class in C++

I have a homework and its just bugging for the last 2 days, I've been doing exactly what the pseudo code and still haven't got it right yet.
For example, if I put in "mike]" or "mike]123", my program will crash, due to the stack is empty...From what I observe, the program will crash when:
- The stack is empty
- And there is a close parenthesis
PS: with the help of us2012, I can fix the crash problem. However, the result is not right.
Instead of printing out "invalid", it outputs "valid"
:(
Here is the pseudo code from my professor:
def parse_parenthesis(str):
stack = create a new empty stack of OpenParen objects
for i from 0 to str.size() - 1:
if str[i] is an open parenthesis
stack.push(new OpenParen(str[i]))
else if str[i] is not a close parenthesis:
# str[i] is not a parenthesis of any kind, so ignore it
continue
# otherwise str[i] must be a close parenthesis, try to
# match it with the most recent open paren, on the top
# of the stack
else if stack is empty
return false;
else if stack.peek() is of the same type as str[i]:
# close properly
stack.pop()
else
return false;
if stack is not empty
return false;
else
return true
and here is what I have so far:
.cpp file
bool ParenMatching(const string& s, unique_ptr<string>& output)
{
unique_ptr<OpenParen> stack(new OpenParen);
bool validOpen, validClose, valid;
bool match; //haveCloseParen;
/*string unMatch = "Unmatch";
string unExpected = "Unexpected close paren";
string noError = "No Error";*/
for (size_t i = 0; i < s.length(); i++)
{
// check if its open parenthesis
validOpen = stack->IsOpenParen(s[i]);
// check if its close parenthesis
validClose = stack->IsCloseParen(s[i]);
// if there is open paren, push into the stack
if(validOpen)
stack->PushObj(s[i]);
else if(!validClose)
{
continue;
}
else if(stack->GetObj().IsEmpty())
valid = false;
else if(match = IsMatchParen(s[i], stack))
stack->PopObj();
else
valid = false;
}
if(!stack->GetObj().IsEmpty())
valid = false;
else
valid = true;
return valid;
}
bool IsMatchParen(const char c, const unique_ptr<OpenParen>& stack)
{
bool valid;
if(c == ')' && stack->PeekObj() == '(')
valid = true;
else if (c == ']' && stack->PeekObj() == '[')
valid = true;
else if (c == '}' && stack->PeekObj() == '{')
valid = true;
else if (c == '>' && stack->PeekObj() == '<')
valid = true;
else
valid = false;
return valid;
}
OpenParen.cpp
// Check if its open paren
bool OpenParen::IsOpenParen(const char c)
{
bool isOpen;
if(c == '(' || c == '[' || c == '{' || c == '<')
isOpen = true;
else
isOpen = false;
return isOpen;
}
// check if its close paren
bool OpenParen::IsCloseParen(const char c)
{
bool isClose;
if(c == ')' || c == ']' || c == '}' || c == '>')
isClose = true;
else
isClose = false;
return isClose;
}
gcc 4.7.3: g++ -Wall -Wextra -std=c++0x parens.cpp
#include <iostream>
#include <stack>
#include <string>
#include <vector>
bool isOpen(char c) {
return c == '(' || c == '[' || c == '{' || c == '<'; }
bool isClose(char c) {
return c == ')' || c == ']' || c == '}' || c == '>'; }
bool isMatch(char c1, char c2) {
return (c1 == '(' && c2 == ')')
|| (c1 == '[' && c2 == ']')
|| (c1 == '{' && c2 == '}')
|| (c1 == '<' && c2 == '>'); }
bool parse(const std::string& s) {
std::stack<std::string::value_type> stk;
for (std::string::size_type i = 0; i < s.size(); ++i) {
if (isOpen(s[i])) { stk.push(s[i]); }
else if (isClose(s[i])) {
if (!stk.empty() && isMatch(stk.top(), s[i])) { stk.pop(); }
else { return false; } } }
return stk.empty(); }
int main() {
std::vector<std::string> ptests = {
"", "()", "()()", "(())", "a(a)a" };
std::vector<std::string> ftests = {
"(", ")", ")(", ")()(", "))((" };
for (const auto& t : ptests) {
if (!parse(t)) { std::cout << "fail: " << t << std::endl; } }
for (const auto& t : ftests) {
if (parse(t)) { std::cout << "fail: " << t << std::endl; } }
}
One important thing you should keep in mind about C++ : Multiple else ifs do not live at the same level. That's because else if is not a single entity, it's an else that belongs to the preceding statement and an ifthat begins a new statement, so
if (cond1)
a();
else if (cond 2)
b();
else if (cond 3)
c();
else
d();
is actually
if (cond1)
a();
else {
if (cond 2)
b();
else {
if (cond 3)
c();
else
d();
}
}
Therefore, your check whether the stack is empty needs to be before the check whether the current close parens matches the top of the stack. Otherwise, your program will try to examine the top of the stack when it's empty, and that results in a crash.
Also, setting valid = false is not the right thing to do when you find a condition that indicates a non-match. The loop will still continue and can reset valid to true in a later iteration. You need to immediately return false, as you can already see in your pseudocode.