Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save multiple regex buffers in variables in Ruby?

Tags:

regex

ruby

In Perl I can do the below and get the expected output admin1secretpw.

How do I do the same in Ruby? I.e. save multiple buffers in variables.

#!/usr/bin/perl

my $a = 'admin1:[email protected]';

(my $u = $1, my $p = $2) if $a =~ /(.*?):(.*?)@/;

print $u;
print $p;
like image 455
Jasmine Lognnes Avatar asked Dec 23 '16 22:12

Jasmine Lognnes


2 Answers

You can use named capture groups.

a = 'admin1:[email protected]'     
/(?<username>.*?):(?<password>.*?)@/ =~ a

puts username
puts password

This captures both groups as local variables.

The order of arguments to =~ matters. Using ... =~ a assigns the named groups to local variables, using a =~ ... won't.

like image 128
akuhn Avatar answered Nov 19 '22 04:11

akuhn


Please see the end for an important note on Perl code. With Ruby you can do

u, v = a.match(/(.*?):(.*?)@/)[1,2]

Here String#match is used. It recongizes /.../ as a regex, converts it to a Regexp object, and then invokes Regexp's match method on it. That returns a MatchData object, which acts as an array. Indexing with 0 gives the whole matched string while 1,2... access array elements.

If a match fails nil is returned so you can test for that, by if u.nil? from NilClass.

An altogether cleaner way may be

if matched = a.match(/(.*?):(.*?)@/)
    u, v = matched.captures
end

which uses MatchData#captures method. Or, you can use $1 and $2 inside the block.

Note that any code that defines symbols via regex matches on external data needs to test them.

There are other ways to do this in Ruby. As a curious example, you can do

u, v = (/(.*?):(.*?)@/).match(a)[1,2]

Here /.../ constructs a Regexp object and then its match method is invoked.

This can also be done nicely without regex, using String#split

u, v = a.split(/:|@/)[0..1]

The string a is split using either : or @ as a delimiter.


The question is stated with Perl code in a way that needs to be cleared up.

It appears that you intend to declare and assign conditionally. A statement such as my $x = 1 executes in two parts -- the declaration happens at compile time, while the assignment goes at runtime. Or, with that condition, it may not.

So, if the assignment doesn't happen at all ... then what value do we have? Also, the condition formally implies that the declaration may not happen at all, which is impossible (the declaration does happen at compile time, before the if is even considered); this makes the whole statement broken in a sense.

From Statement Modifiers in perlsyn (original emphasis)

NOTE: The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, my $x if ... ) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

So you do not want to do that in Perl. Besides, regex gives you that for free

my ($u, $v) = $var =~ /(.*?):(.*?)@/;

Now test $u and $v. You can also do that in the same statement, if you wish

if ( my ($u, $v) = $var =~ /(.*?):(.*?)@/ ) { 
    print "$u, $v\n";
}

The condition is true only if both $u and $v are true. This may be very handy since $u and $v are now scoped in a convenient way but it can also be tricky if the regex can match and leave a variable(s) falsey, so use with care.


That would be processed in the sense of ( my $var = ... ) if ...

like image 21
zdim Avatar answered Nov 19 '22 03:11

zdim