I have to write a program to check for balanced HTML tags here is what i have so far. My problem is it is not working right. My stack implementation is fine, i believe my problem is when i am looping through the string ( lines58-70 I marked with comments where i think the problem is any help would be greatly appreciated.

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

#define MAX 300


typedef struct stack
{
int item[MAX];
int Top;
}STACK;
 void push(STACK *ps, int x)
    {
        if (ps->Top == MAX) {
            fputs("Error: stack overflow\n", stderr);
            abort();
        } else
            ps->item[ps->Top++] = x;
    }
        int pop(STACK *ps)
    {
        if (ps->Top == 0){
            fputs("Error: stack underflow\n", stderr);
            abort();
        } else
            return ps->item[--ps->Top];
    }

int main ()
{
    
    size_t pos1;
    size_t pos;
    string str, tmp;
    std::string filename;

    cout <<"Please enter the name of the file" << endl; 
	cin >> filename;
  
	ifstream myfile(filename.c_str());
	while(getline(myfile, tmp))
	{
	str += tmp;
    }
   
  

 STACK stack;
  stack.Top = 0;
  
  
  pos1= 0;
  pos = 0;   
                               // I believe my problem is with the below code
  while (pos != string::npos)
  {      
  
    if (pos=str.find("<" && ">",pos+1))   
   push(&stack, 1);
}

while (pos1 != string::npos)
  {      
   
   if (pos1=str.find("</" && ">",pos1+1))     
    pop(&stack);
}


 
 

 if (stack.Top == 0)
 { 
            cout << "Legal" << endl;
            }
   else
   {
         cout << "Illegal" << endl;

}
system("pause>nul");
  return 0;
}

Dani AI

Generated

You are bumping into two separate issues here. First, str.find("<" && ">", pos+1) does not search for a pair of characters. The operands "<" and ">" are pointers; && turns them into the boolean true and you end up calling find for the character with value 1. Also, if (pos = str.find(...)) assigns, not compares. If a tag starts at offset 0, the if condition is false and you skip it. As hinted, find the next <, then the next >, and work with the substring in between. Second, as noted, counting opens and closes is not enough; you must match tag names and nesting.

Here is a minimal approach that pushes real tag names and handles </x>, <!-- ... -->, and self-closing tags. It also ignores <!...> and <?...?> constructs. Keep it simple for your assignment; you can extend void-tag handling later.

#include <bits/stdc++.h>
using namespace std;

bool balanced(const string& html) {
    vector<string> st;
    unordered_set<string> voids = {"br","hr","img","input","link","meta"};
    for (size_t i = 0; i < html.size(); ) {
        if (html.compare(i,4,"<!--") == 0) {
            size_t k = html.find("-->", i+4);
            if (k == string::npos) return false;
            i = k + 3; continue;
        }
        if (html[i] != '<') { ++i; continue; }
        size_t j = html.find('>', i+1);
        if (j == string::npos) return false;

        string t = html.substr(i+1, j-i-1);
        i = j + 1;

        auto l = t.find_first_not_of(" \t\r\n");
        auto r = t.find_last_not_of(" \t\r\n");
        if (l == string::npos) continue;
        t = t.substr(l, r-l+1);
        if (t[0] == '!' || t[0] == '?') continue;

        bool closing = t[0] == '/';
        bool selfclose = !closing && !t.empty() && t.back() == '/';
        size_t start = closing ? 1 : 0;
        size_t end = t.find_first_of(" \t/>", start);
        string name = t.substr(start, end-start);
        for (auto& c : name) c = (char)tolower(c);

        if (closing) {
            if (st.empty() || st.back() != name) return false;
            st.pop_back();
        } else if (!selfclose && !voids.count(name)) {
            st.push_back(name);
        }
    }
    return st.empty();
}

Debug tip: print each extracted name and the action (push/pop) as you parse so you can see exactly where the first mismatch appears. This will also make it obvious why simple counts can report balanced even when tags cross, e.g., <a><b></a></b>.

Recommended Answers

All 11 Replies

And what is if (pos=str.find("<" && ">",pos+1)) supposed to do?

You said "My problem is it is not working right" which is fine but tells us absolutely nothing. So I waited with bated breath for what it was doing wrong. All I got was "it seems to be here". Please, when asking for help, also explain the problem.

Ok sorry if (pos=str.find("<" && ">",pos+1)) is supposed to find where a tag is in the string i.e. <...> like a html tag but when i run the program nothing happens.

So my question would be are you able to do if (pos=str.find("<" && ">",pos+1)) the way i have it done? and if you are not what would be a better way to do this?

Find the '<', then find the '>'. Extract (copy) the substring between them.

Quick question, What is the data that you are trying to store in the stack ? 1's or the content b/w the < .... > tags ?

If you going to store just 1's then your program will break for

<html>
  <a>
       My text
  </b>
</xml>

Storing the content b/w the < .., > tags will require you to modify your data structure

Hey abhimanipal not trying to store the content between the < ... > just trying to make it push for < ... > and pop for </ ... > when ever come across one of them when it reads through the sting. Then at the end of the program if the stack.Top == 0 meaning there are a correct number of each tags it will print the result. But it is not working correctly.

thanks in advance for the help.

What is the error that you are getting ? Did you try to debug ?

Not getting a error it complies fine but as Waltp said my code is wrong because you cant do

while (pos != string::npos)
  {      
 
    if (pos=str.find("<" && ">",pos+1))   
   push(&stack, 1);
}
 
while (pos1 != string::npos)
  {      
 
   if (pos1=str.find("</" && ">",pos1+1))     
    pop(&stack);
}

the way i have it written. Any suggestions on how to fix it would be appreciated.

What is the if statement supposed to do ?

The if statement us supposed to check if there are a set of tags like<> or </> and then push or pop like kit adds one to the stack if it see s <> and then it pop s one if it sees </>

Is the if statement working correctly ?

Print the results that you get after using the find . Also I see that you have a single = sign in the if block . Is this what you want ?

Not getting a error it complies fine but as Waltp said my code is wrong because you cant do...
[snip]
the way i have it written. Any suggestions on how to fix it would be appreciated.

This should help

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.