birgit kellner <[EMAIL PROTECTED]> writes:

> Many thanks to "Wagner-David" for the code. I've slightly changed it,
> as below, but have still further questions.

[...]

> ... checking on an initial digit is not specific enough, because in
> between a heading "$counter" and the next subheading "$counter.1",
> there might be a line beginning with "$counter" = a list entry. I
> really need to do a loop moving up a counter, *and* I need the
> search to be "position-aware".
> 
> I guess my question boils down to: How to code "when there's a match
> of "1\.\s" in the beginning of a line, check whether there's a
> "1\.1\.\s" after the end of that line - if so, assign everything in
> between the end of that line and "1\.1\.\s." as a hash value, and
> move up the counter to 2; if not, move up the counter to 2 and
> search for a line beginning with "2\.\s" *after* "1\.1\.\s". "

Let's do some exploration. I'm going to ignore the requirement for
grabbing the text in a section for now, let's deal with the hard bit.
First we'll need a '@counters' array, it can hold the current values
of our section numbers. Since 0 isn't a valid section number we'll
initialize it like so:

    my @counter = (0);

This is our state variable.

Now, let's say we have a 'candidate' string that might be a valid
section number. We found it by matching:

    my($candidate) = /((?:(?:^|\.)\d+)+)/

In general we have several possible legal strings that could match, let's
say the last section number we saw was 1.1, then our possibles are:
1.2, 1.1.1, or 2, so lets build our possible patterns

    my $section_incremented_pattern = 
       '^' . join("\\.",
                  @counter[0..($#counter - 1)], $counter[-1] + 1) . '$';

    my $new_section_pattern = 
       '^' . join("\\.", @counter, 1) . '$';

These two are easy, all we have to do with these is:

    if ($candidate =~ $section_incremented_pattern) {
        $counter[-1]++; # Increment the last counter in @counter;
    }
    elsif ($candidate =~ $new_section_pattern) {
        push @counter, 1; # Add a new section counter.
    }
    else {
        ...
    }

So, the trick here is working out what to replace the ... with. Which
is left as an exercise to the interested reader. 

Yeah, right.

Okay, this time we match candidate against the current counter.
First we'll split $candidate.

    my @possible_counter = split /\./, $candidate;

Okay, now, if $candidate is legal then @possible_counter will be
shorter than @counter:

    return unless @possible_counter < @counter;

And every element of @possible_counter will be the same as @counter,
except for its last element, which will be one more than the
equivalent element of @counter.

    $possible_counter[-1]--;

    for my $i (0..$#@possible_counter) {
        $possible_counter[$i] == $counter[$i] or return;
    }

If we reach this point we have a legal string, so we reset
@possible_counter and replace @counter with it.

    $possible_counter[-1]++;
    @counter = @possible_counter;

    return "Success!";

Now all you have to do is put all that together. And my train's
arriving at the station, so I'll leave that up to you. Hopefully the
code snippets above should point you in the right direction.

-- 
Piers

   "It is a truth universally acknowledged that a language in
    possession of a rich syntax must be in need of a rewrite."
         -- Jane Austen?

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to