in reply to Pair Tag missing

Contrary to jpeg's suggestion, I'd suggest that you use a stack for keeping track of tags. Each time you see an open-tag, push it on the stack; each time you see a close tag, check the last thing on the stack and see if it's the same sort of tag.

If it's a match, you're fine, and you can pop that last element off the stack and move on. If it's not a match, the next issue is: for this unmatched end-tag, check further along the stack to see if you do find a matching open tag; if so, then all open tags from that point to the end are probably lacking their end-tags. If the current end tag has no match at all in the stack, then you know you're missing an open tag for it.

And to contradict jpeg yet again, here's an example of the technique:

#!/usr/bin/perl use strict; $/=undef; $_=<>; my @stack = (); my $offset = 0; while (( my $i = index( $_, "<" )) >= 0 ) { $offset += $i; $_ = substr( $_, $i ); if ( s{^(<(\w+).*?>)}{} ) { $offset += length( $1 ); push @stack, $2; } elsif( s{^(</(\w+)>)}{} ) { my $et = $2; if ( $stack[$#stack] eq $et ) { pop @stack; } elsif ( grep( /$et/, @stack )) { print "missing end-tags for:"; while ( @stack and $stack[$#stack] ne $et ) { print " ".pop @stack; } print " at </$et> (offset: $offset)\n"; } else { print "missing open-tag for $et (offset: $offset)\n"; } $offset += length( $1 ); } } ### updated: added condition on inner while loop to check for empty st +ack
Now, the results printed by that approach can be inaccurate or misleading under certain circumstances, but you will at least get a reasonable look at where the problems start.

And of course, if you have data with lots of elaborate stuff in the tags (e.g. a close-angle-bracket inside a quoted string that is part of an attribute value in an open tag), then this approach will be thrown off totally, and you'll need to parse the input more carefully. Good luck with that.

(One more update: it's possible that there might be open-angle brackets in the text, which are not intended as the beginning of a tag -- this isn't supposed to happen, the text is supposed to use "&lt;" instead of a bare "<", but hey, it happens, and it will also cause this script to fail, or at least create a lot of false-alarm error reports. Perhaps that's just as well...)

Replies are listed 'Best First'.
Re^2: Pair Tag missing
by Elijah (Hermit) on May 31, 2005 at 14:44 UTC
    This method is extremely flawed. What if you are parsing data that has mathematical equations using the less than or greater than sign? Yes standard html 4.01 transitional should have &lt; and &gt; instead of the actual sign but we all know this will not be the case more times then not.

    What if the data has arraws in it (<-- -->)? What if I have my email address in the data as such: <ziationATperlskriptsDOTcom>? Good luck finding a closing tag for that. What if I have some perl code snippets in my data and am assigning STDIN ($var = <> or <STDIN>)? There are many many possiblitites where your code could go tits up and the results would be seriously scewed.