| Author |
Recursively counting a matching pattern on a single line.
|
|
| S.A. Birl 2004-10-27, 8:55 pm |
| Given a bookmark:
<DT><A HREF="http://www.perl.com/CPAN-local/doc/FAQs/FAQ/PerlFAQ.html" ADD_DATE="897592292" LAST_VISIT="982769648" LAST_MODIFIED="982769648" ID="rdf:#$rsy5Z">PERL FAQ</A>
Wondering if it's possible to have 2 counters that would keep track of the
number of < and > encountered.
Im looking to see if there's a balance of < and >, and scream as soon as
there isnt a balance.
So given the above bookmark, I know that there's 3 < and 3 >
and the pattern is basically <><><> and not <<>> or >><, etc.
Thanks
Birl
| |
| Bob Showalter 2004-10-27, 8:55 pm |
| S.A. Birl wrote:
> Given a bookmark:
>
> <DT><A
> HREF="http://www.perl.com/CPAN-local/doc/FAQs/FAQ/PerlFAQ.html"
> ADD_DATE="897592292" LAST_VISIT="982769648" LAST_MODIFIED="982769648"
> ID="rdf:#$rsy5Z">PERL FAQ</A>
>
>
> Wondering if it's possible to have 2 counters that would keep track
> of the
> number of < and > encountered.
>
> Im looking to see if there's a balance of < and >, and scream as soon
> as
> there isnt a balance.
>
> So given the above bookmark, I know that there's 3 < and 3 >
> and the pattern is basically <><><> and not <<>> or >><, etc.
If you're specifically looking whether the brackets follow the pattern
<><><>, could you just do something like:
my $brackets = join '', $bookmark =~ /[<>]/g;
die "Bad pattern" unless $brackets eq '<><><>';
| |
| Brian Barto 2004-10-27, 8:55 pm |
| Assign each line to the $_ variable and try this to get the number of
instances of < and >
The match operator works on $_ by default. If you match on < or > globally
and assign it to an array like so:
@rights = m/\</g;
@lefts = m/\>/g;
You are left with arrays that contain all the matches. Now all you need to
do is count the number of elements in each array like so:
$number_of_rights = $#rights;
$number_of_lefts = $#lefts;
Then compare them:
if ($number_of_rights != $number_of_lefts)
{
## scream here!!
}
-----Original Message-----
From: S.A. Birl [mailto:sbirl+PERL@concept.temple.edu]
Sent: Wednesday, October 27, 2004 3:23 PM
To: beginners@perl.org
Subject: Recursively counting a matching pattern on a single line.
Given a bookmark:
<DT><A HREF="http://www.perl.com/CPAN-local/doc/FAQs/FAQ/PerlFAQ.html"
ADD_DATE="897592292" LAST_VISIT="982769648" LAST_MODIFIED="982769648"
ID="rdf:#$rsy5Z">PERL FAQ</A>
Wondering if it's possible to have 2 counters that would keep track of the
number of < and > encountered.
Im looking to see if there's a balance of < and >, and scream as soon as
there isnt a balance.
So given the above bookmark, I know that there's 3 < and 3 >
and the pattern is basically <><><> and not <<>> or >><, etc.
Thanks
Birl
--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
<http://learn.perl.org/> <http://learn.perl.org/first-response>
| |
| S.A. Birl 2004-10-27, 8:55 pm |
| On Oct 27, brian.barto@spectrum-health.org (nospam-brian.barto@spectrum-hea...:
Brian: Assign each line to the $_ variable and try this to get the number of
Brian: instances of < and >
Brian:
Brian: The match operator works on $_ by default. If you match on < or > globally
Brian: and assign it to an array like so:
Brian:
Brian: @rights = m/\</g;
Brian: @lefts = m/\>/g;
Brian:
Brian: You are left with arrays that contain all the matches. Now all you need to
Brian: do is count the number of elements in each array like so:
Brian:
Brian: $number_of_rights = $#rights;
Brian: $number_of_lefts = $#lefts;
Brian:
Brian: Then compare them:
Brian:
Brian: if ($number_of_rights != $number_of_lefts)
Brian: {
Brian: ## scream here!!
Brian: }
Great! That works. But I was looking to get a little trickier with it.
If I had:
<DT <A HREF="http://www.perl.com/CPAN-local/doc/FAQs/FAQ/PerlFAQ.html" ADD_DATE="897592292" LAST_VISIT="982769648" LAST_MODIFIED="982769648" ID="rdf:#$rsy5Z">PERL FAQ</A>
I wanted it to scream when it reached the 2nd < ; stopping the pattern
matching from continuing any further. Is that possible, or would
something more complex be needed?
If it's too complex, I'll just with what I have for now.
Thanks
Birl
Please do not CC me responses to my own posts.
I'll read the responses on the list.
| |
| Brian Barto 2004-10-27, 8:55 pm |
| Great! That works. But I was looking to get a little trickier with it.
----------------
If you want to make sure they are alternating like <><><> etc... I would do
this:
$_ = $line;
@syms = m/[<>]/g;
$string = join("", @syms);
if ($strings !~ m/^<(>< )*>$/)
{
## Scream here!
}
The regular expression:
m/^<(>< )*>$/
will ensure that it starts with < and ends with > and anything in between
will be "><" which I think should do the trick. That logic is pretty hairy
though and I could be missing something.
| |
| Brian Barto 2004-10-27, 8:55 pm |
| Correction: "$strings" in the if statement should be "$string"
-----Original Message-----
From: brian.barto@spectrum-health.org
[mailto:brian.barto@spectrum-health.org]
Sent: Wednesday, October 27, 2004 4:04 PM
To: beginners@perl.org
Subject: RE: Recursively counting a matching pattern on a single line.
Great! That works. But I was looking to get a little trickier with it.
----------------
If you want to make sure they are alternating like <><><> etc... I would do
this:
$_ = $line;
@syms = m/[<>]/g;
$string = join("", @syms);
if ($strings !~ m/^<(>< )*>$/)
{
## Scream here!
}
The regular expression:
m/^<(>< )*>$/
will ensure that it starts with < and ends with > and anything in between
will be "><" which I think should do the trick. That logic is pretty hairy
though and I could be missing something.
--
To unsubscribe, e-mail: beginners-unsubscribe@perl.org
For additional commands, e-mail: beginners-help@perl.org
<http://learn.perl.org/> <http://learn.perl.org/first-response>
| |
| S.A. Birl 2004-10-27, 8:55 pm |
| On Oct 27, brian.barto@spectrum-health.org (nospam-brian.barto@spectrum-hea...:
Brian:
Brian: If you want to make sure they are alternating like <><><> etc... I would do
Brian: this:
Brian:
Brian: $_ = $line;
Brian:
Brian: @syms = m/[<>]/g;
Brian: $string = join("", @syms);
Brian: if ($strings !~ m/^<(>< )*>$/)
Brian: {
Brian: ## Scream here!
Brian: }
Brian:
Brian: The regular expression:
Brian:
Brian: m/^<(>< )*>$/
Brian:
Brian: will ensure that it starts with < and ends with > and anything in between
Brian: will be "><" which I think should do the trick. That logic is pretty hairy
Brian: though and I could be missing something.
Wouldnt m/[<>]/g literally match <> and not <characters>?
Why wouldnt it be m/[<.+>]/g ?
Thanks
Birl
Please do not CC me responses to my own posts.
I'll read the responses on the list.
| |
| Brian Barto 2004-10-27, 8:55 pm |
|
Wouldnt m/[<>]/g literally match <> and not <characters>?
Why wouldnt it be m/[<.+>]/g ?
Thanks
Birl
-----------
Someone correct me if I'm wrong but putting characters inside brackets []
defines a character class. Or a group of characters you want to match on,
not necessarily in that order.
For instance m/[0-9]/g matches on any single digit number, not "0123456789"
| |
| Gunnar Hjalmarsson 2004-10-27, 8:55 pm |
| S.A. Birl wrote:
> Wondering if it's possible to have 2 counters that would keep track
> of the number of < and > encountered.
>
> Im looking to see if there's a balance of < and >, and scream as soon
> as there isnt a balance.
>
> So given the above bookmark, I know that there's 3 < and 3 > and
> the pattern is basically <><><> and not <<>> or >><, etc.
Assuming that you are actually not interested in *counting* them, this
is one approach:
print "Oops!\n" unless $string =~ /^[^<>]*(?:(?:<[^<>]*> )*[^<>]*)*$/;
--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
| |
| John W. Krahn 2004-10-27, 8:55 pm |
| brian.barto@spectrum-health.org wrote:
> Assign each line to the $_ variable and try this to get the number of
> instances of < and >
>
> The match operator works on $_ by default. If you match on < or > globally
> and assign it to an array like so:
>
> @rights = m/\</g;
> @lefts = m/\>/g;
See the FAQ for a more efficient way to do this.
perldoc -q "How can I count the number of occurrences of a substring within a
string"
> You are left with arrays that contain all the matches. Now all you need to
> do is count the number of elements in each array like so:
>
> $number_of_rights = $#rights;
> $number_of_lefts = $#lefts;
An array in scalar context returns the number of elements in that array. You
are using the index of the last element of the array which *may* (or may not!)
be one less than the number of elements.
John
--
use Perl;
program
fulfillment
| |
| John W. Krahn 2004-10-27, 8:55 pm |
| S.A. Birl wrote:
> On Oct 27, brian.barto@spectrum-health.org (nospam-brian.barto@spectrum-hea...:
>
> Brian: The regular expression:
> Brian:
> Brian: m/^<(>< )*>$/
> Brian:
> Brian: will ensure that it starts with < and ends with > and anything in between
> Brian: will be "><" which I think should do the trick. That logic is pretty hairy
> Brian: though and I could be missing something.
>
> Wouldnt m/[<>]/g literally match <> and not <characters>?
Anything inside [ and ] is a character class and will match either '<' or '>'
anywhere in the string.
> Why wouldnt it be m/[<.+>]/g ?
That will match the characters '<' or '.' or '+' or '>'.
John
--
use Perl;
program
fulfillment
| |
| Zeus Odin 2004-10-27, 8:55 pm |
| What I think you are actually saying is that you want to know when you
encounter two <'s or two >'s in a row You then want the program to alert and
exit. The following accomplishes this. Apologies if I misunderstood.
-ZO
-----
#!/usr/bin/perl
use warnings;
use strict;
my $count;
my $text = '<DT <A HREF=' .
'"http://www.perl.com/CPAN-local/doc/FAQs/FAQ/PerlFAQ.html" ' .
'ADD_DATE="897592292" LAST_VISIT="982769648" ' .
'LAST_MODIFIED="982769648" ID="rdf:#$rsy5Z">PERL FAQ</A>';
for my $pos(0 .. length($text)-1) {
$count++ if substr($text, $pos, 1) eq '<';
$count-- if substr($text, $pos, 1) eq '>';
die "Imbalanced tags at position $pos\n" if abs $count > 1;
}
print "Tags are balanced!\n"
"S.A. Birl" <sbirl+PERL@concept.temple.edu> wrote in message ...
> Great! That works. But I was looking to get a little trickier with it.
>
>
> If I had:
> <DT <A HREF="http://www.perl.com/CPAN-local/doc/FAQs/FAQ/PerlFAQ.html"
ADD_DATE="897592292" LAST_VISIT="982769648" LAST_MODIFIED="982769648"
ID="rdf:#$rsy5Z">PERL FAQ</A>
>
> I wanted it to scream when it reached the 2nd < ; stopping the pattern
> matching from continuing any further. Is that possible, or would
> something more complex be needed?
| |
| Gunnar Hjalmarsson 2004-10-27, 8:55 pm |
| Gunnar Hjalmarsson wrote:
>
> print "Oops!\n" unless $string =~ /^[^<>]*(?:(?:<[^<>]*> )*[^<>]*)*$/;
Hmm.. That got unnecessarily complicated. Make it:
print "Oops!\n" unless $string =~ /^[^<>]*(?:<[^<>]*>[^<>]*)*$/;
--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl
|
|
|
|