Parsing blocks of text in Perl

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
OK, so every way I've thought of doing this is really ugly.  I'm using
Perl 5.8.4 and only have access to the stock libraries, mostly.

What I need to do is parse through a text file and perform some
transformations on embedded link structures for a wiki content
conversion.  A "link" is defined as anything wrapped in double
brackets - [[<string>]], which can appear anywhere in a line of text
and multiple links can appear in a line of text.

1) If the link has a colon (":") in it, I need to strip out all
special characters and spaces (everything except [a-zA_Z0-9]) from the
portion before the colon but leave the part after the colon intact.
[[Operation Intranet 2.0!:EvalHome|Eval Home]] -->
[[OperationIntranet20:EvalHome|Eval Home]]
[[UP Platform:Home|UP Platform]] --> [[UPPlatform:Home|UP Platform]]

2) If the link does not have a ":" in it, I need to insert the string
General: before the name of the page.
[[Technical FAQs|Technical FAQs]] --> [[General:Technical FAQs|
Technical FAQs]]
[[Embedded - Top 5 content|Top 5 content]]    [[General:Embedded - Top 5
content|Top 5 content]]

3) Special case - don't change if it is an image link or if it is an
external link (only single [] enclosure).
[[Image:BIhouse.jpg]] --> [[Image:BIhouse.jpg]]
[ SPSS Wiki] --> [http:// SPSS Wiki]

I expect this is similar to some HTML parsing requirements, but I've
been hunting through my O'Reilly Perl books and Googling and I'm
having trouble finding my way.  Normal regexp replace appears not to
be the way to go and I'm having greediness issues.   Ideas?


Re: Parsing blocks of text in Perl

On Wed, 5 Mar 2008 12:35:43 -0800 (PST),
Quoted text here. Click to load it

This implies that they cannot span more than one line of text, which is
what I assumed.

Quoted text here. Click to load it

Removing everything except a-zA-Z0-9 from 'Image' doesn't change it.

Quoted text here. Click to load it

Avoiding looking at single brackets would be easiest.

Quoted text here. Click to load it

This is not nearly as complex as HTML, unles you haven't yet given us
all possible problems. I'm pretty sure that a regex can do that, and
greediness issues should, in this case, be simply fixable by using
non-greedy modifiers. If you have an example that doesn't get correctly
handled by the below, let us know.

Next time, before you post here, show us what you have tried first. This
is not a place where you can coe to get free code all the time, and if
you don't show us what you have tried, it looks like that is exactly
what you're trying to do.

For this time:

use warnings;
use strict;

while (<>)
    s/\[\[(.*?)\]\]/'[[' . replace_link($1) . ']]'/ge;

sub replace_link
    my @link = split ':', shift;
    if (@link == 1)
    unshift @link, 'General';
    $link[0] =~ tr/a-zA-Z0-9//dc;

    return join ':', @link;

This can probably be made a bit faster, by avoiding splitting and
joining, but unless it's a problem I wouldn't worry about it. The
mechanism remains the same, and you shold be easily able to adjust
replace_link to taste. You could also avoid having to put the brackets
back by using look-(ahead|behind) assertions instead, but I generally
find this more readable. If links can cross line bondaries, and files
aren't too large, read the whole file in, and run the body of the while
loop on that.

Martien Verbruggen      | Blessed are the Fundamentalists, for they
                        | shall inhibit the earth.

Re: Parsing blocks of text in Perl

Martien Verbruggen wrote:
Quoted text here. Click to load it

That's good advice.

Quoted text here. Click to load it

Isn't it? You just made me believe it is. ;-)

Gunnar Hjalmarsson

Site Timeline