Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: difference in regex

by Athanasius (Archbishop)
on May 29, 2018 at 13:42 UTC ( [id://1215367]=note: print w/replies, xml ) Need Help??


in reply to difference in regex

Hello ovedpo15,

In Perl, a function’s return value(s) may be different depending on the context in which the function is called. (Whether they are or not depends on the internal details of the function itself.) The statement my $value = $row =~ /.*,(.*)/; calls the regex operator m// in scalar context, so it returns true if the match succeeds and false if it fails. But in the statement my ($value) = $row =~ /.*,(.*)/; the parentheses around $value put the call to m// into list context and a list of the matches is returned.

By contrast, the substitution operator s/// returns the number of substitutions made regardless of the calling context. But you can change this behaviour by adding an /r modifier to the substitution. This creates a copy of the string (in this case $row), applies the substitutions (if any) to the copy, and returns that copy. E.g.

my $row = 'a,b,c,d,15'; my $str = $row =~ s/,[^,]*$//r; # $str now contains 'a,b,c,d'

See the sections m/PATTERN/msixpodualngc and s/PATTERN/REPLACEMENT/msixpodualngcer in perlop#Regexp-Quote-Like-Operators.

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Replies are listed 'Best First'.
Re^2: difference in regex
by ovedpo15 (Pilgrim) on May 29, 2018 at 13:58 UTC
    Thank you for the fast replay.
    I tried to use the following regex  my($path,$value) = ($row =~ /(.*),(.*)/); to split the string.
    but if there are no commas it won't work. Which regex should I use in order to always put the string into $path so I can only check if $value is defined?
    for example:
    if "abc" it will be $path = "abc" and $value is undefined.
    if "abc,5" it will be $path = "abc" and $value = 5
    if "a,b,c,5" it will be $path = "a,b,c" and $value = 5

    The algo I would like to implement :
    As I see it the steps are:
    1. if the string has commas:
    1.a. get the last comma and check if the last substring is a number - if so put it in hash like this: $hash{$path} = $value;
    1.b. if the substring after the last comma isn't a number - $hash{$path} = 1;
    2. if string has no commas: $hash{$string} = 1;


    how to implement this?

      Because ($path, $value) is a list, you get the list of submatches (list context). But if you do something like:

      if ($row =~ /(.*),(.*)/) { ... }
      since the if expects a boolean, the operation will return true if something matches, and false otherwise (boolean context). And you can still access the left and right part as $1 and $2. So you can do:
      my $path = $row; # path is the full string by default if ($row =~ /(.*),(.*)/) { my $left_part = $1; my $value = $2; # Check if $value is a number and change $path if needed ... }

      The algo I would like to implement :
      As I see it the steps are:
      1. if the string has commas:
      1.a. get the last comma and check if the last substring is a number - if so put it in hash like this: $hash{$path} = $value;
      1.b. if the substring after the last comma isn't a number - $hash{$path} = 1;
      2. if string has no commas: $hash{$string} = 1;

      Although a good start, point 1.b. is unclear: in this case, do you want the whole string stored in $path, or just the part up until the last comma? For now I'm assuming the latter. Anyway, while there may always be "nicer" ways to write things in Perl (Update: and you haven't specified what you meant with "it doesn't look very good"), sometimes a good starting point is a direct translation:

      use warnings; use strict; use Scalar::Util qw/looks_like_number/; use Data::Dumper; # Debug my %hash; while (my $string = <DATA>) { chomp($string); # check if string has at least one comma, and at the same # time extract the value after the last comma if ( my ($path,$value) = $string=~/^(.*),([^,]*)$/ ) { if ( looks_like_number($value) ) { $hash{$path} = $value; } else { $hash{$path} = 1; } } else { $hash{$string} = 1; } } print Dumper(\%hash); # Debug __DATA__ foo bar,x quz,5 a,b,c,42

      Of course there's lots of potential for shortening that, e.g. by combining it with my example code from here. Update: A really simple shortening:

      while (<DATA>) { chomp; if ( /^(.*),([^,]*)$/ ) { $hash{$1} = looks_like_number($2) ? $2 : 1 } else { $hash{$_} = 1 } }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1215367]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (6)
As of 2024-04-19 22:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found