Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,
I am new to Reg Exp. I have to find out the name of the product and the Operating system it supports.
$test="Server list (Win2K/Win2003/XP) 6.26.5.1.5"; $test1="Server list 6.26.5.1.5";
I have to split $test as the part1(server list), part2( Win2k..) and part3 (6.26...). If you take the second string there is know part2.I am using the following RE. It doesn't return any value for string $test1.
$test =~/(.*)(\(.+\))(.*)/); my $prod_name=$1; my $platform=$2; my $version=$3;
Can you please help me to get a reg exp which give part1,part2(if exists) and part3?.
Thanks,

Replies are listed 'Best First'.
Re: Reg Exp
by mwah (Hermit) on May 26, 2008 at 09:36 UTC

    use the non-greedy .+? modifier + the optional group (?: ... )*

    my $test = "Server list (Win2K/Win2003/XP) 6.26.5.1.5"; my $test1 = "Server list 6.26.5.1.5"; # $test =~ /(.*)(\(.+\))(.*)/; my $regexp = qr{ # note: greedy (.+) vs. non-greedy (.+?) +qf. (.+?) # capture what comes but look ahead => $1 \s* # optional whitespace (?: # start optional group (?: ... )? \( # opening bracket ([^)]+) # get what's in the bracket => $2 \) # closing bracket )? # - optional \s* # possibly followed by some whitespace ([\d.]+) # then look for numbers and dots => $3 $ # which is anchored at the string end }x; if( $test =~ /$regexp/ ) { # if( $test1 =~ /$regexp/ ) my ($prod_name, $platform, $version) = ($1, $2, $3); if(defined $platform) { print "$prod_name, $platform, $version" } else { print "$prod_name, <none>, $version" } }

    Regards

    mwa

      Thanks.Your solution is a perfect fit.
Re: Reg Exp
by moritz (Cardinal) on May 26, 2008 at 09:33 UTC
    Of course $test1 doesn't match, because the parenthesis are mandatory in the regex.

    So you have to make them optional. But that menas that the the first .* will suck up all of the regex, so you have to find a compromise. The one I chose below is to allow everything but digits and opening parenthesis in the first chunk:

    #!/usr/bin/perl use strict; use warnings; my @tests = ("Server list (Win2K/Win2003/XP) 6.26.5.1.5", "Server list + 6.26.5.1.5"); for (@tests){ if (m/([^(\d]+) ((?:\([^)]+\))?) (.*)/x){ print "$1|$2|$3\n" } else { print "No match for $_\n"; } } __END__ Server list |(Win2K/Win2003/XP)| 6.26.5.1.5 Server list ||6.26.5.1.5
Re: Reg Exp
by psini (Deacon) on May 26, 2008 at 09:37 UTC

    You could use split, that splits a string into an array using a regex to determine the split position(s), as follow:

    @result=split(/\s+\(|\)\s+/, $string);

    This should split the string at any open parenthesis preceded by one or more spaces, and at any closed parenthesis followed by one or more spaces.

    Rule One: Do not act incautiously when confronting a little bald wrinkly smiling man.

      Hi psini,

      That solution seems to be not fit here. In the 'test1' string, there is no parantheses to split, so it will obviously fail and you can't split the string.

      OP wants to match the 'test1' string where the platform is missing and which is present in 'test' string.

      Prasad

        Yep, I realized it reading the other answers, sorry

        Rule One: Do not act incautiously when confronting a little bald wrinkly smiling man.

        Actually, IFF (if and only if) there are only the 2 variations presented in the OP, you could just use a

        @arr=split(/ /,$test);

        ... and count the size of the array

        $size=scalar(@arr);

        if its 4, arr[2]is the OS, otherwise no OS was specified