in reply to parsing a config file

Basic pattern matching is not the best solution to this situation, but I'll focus on correct pattern matching.

See Programming Perl, Chapter 3, "The Range Operator" (pg 103 in the third edition).

'..' is a boolean operator, which is false by default. Once the left operator returns true, the '..' evaluates to true until the right operator evaluates to true.

As soon as the left operator evaluates to true, stating that the beginning of the range has been reached, the right operator is tested, to see if the end of the active reagion has been reached. That's why you don't get the regions betwween header lines, with '..': as soon as you detect the beginning of the region, it also triggers the end of region.

With '...', end of region is not tested when the start has just been detected, so you do get the regions between the header lines. But since the start and end patterns are the same, and the patterns match several times, you only get some of the regions.

Your file has the structure:

  1. ClientExitPath:
  2. LogDefaults:
  3. QueueManager:
  4. QueueManager:
  5. QueueManager:
  6. QueueManager:

You want to begin printing at header section 3, the first QueueManager. You want to process key/value pairs until you are no longer in a QueueManager section.

Detect the beginning is fine the way you have it. The end of the region you want is marked by encountering a header line which is not a QueueManager header. (Or, of course, end of file) So a simple pattern you want is:

print if /^QueueManager:/ ... (/:/ && ! /^QueueManager:/);

i.e.: Begin printing when you encounter a QueueManager, and continue until you reach a non-QueueManager header line. But this is clumsy and relatively complicated. You COULD be daring and use a closing condition like /^^Q\w*:/, a header line which does not begin with a Q, but what if there's a QueryManager: header line? What you really want is a header line which is not a QueueManager header line. A negative look-behind assertion is perfect for this:

print if /^QueueManager:/ ... /^(?<=:QueueManager):/;

The closing condition is a ':' which follows any string ... any string other than 'QueueManager'.

As a minor style difference, I don't bother matching the '\*$' after the colon.

I typed "negative look-behind assertion", but then in the code I made a typo and used a positive look behind assertion. The code should be /^(?<!:QueueManager):/ ... BUT either a negative or positive look-behind assertion work. How did that happen? Tom

Replies are listed 'Best First'.
Re: Re: parsing a config file
by Gorio3721 (Acolyte) on May 23, 2003 at 21:12 UTC

    Thanks Tom. This is exactly what I was looking for. I guess I have to dig out my 'Masteing Regular Expressions' book and figure out exactly what the heck a negative look-behind assertion really is and then I'll be on my way to becoming a guru!

    At the top of your post you said that basic pattern matching is not the best way to go about this (although it has eductaed me, which was my real intent here). What would be the best approach in your opinion?

    Thanks for the help!!!