Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
$rh->cmd('show interfaces xe-1/3/1 | match "Hardware address" ');
my $output = $rh->get_response;
my @outputlist = split /\n/, $output;
foreach my $item (@outputlist) {
$item =~ /($dd([:-])$dd(\2$dd){4})/o;
print "mac address is $1\n";
my @mac_add = split(/:/, $1 );
print "at mac is @mac_add\n";
my $mac_R5 = join(".", @mac_add);
print " final mac is $mac_R5\n";
output is
mac address is 28:8a:1c:59:cc:85
at mac is 28 8a 1c 59 cc 85
final mac is 28.8a.1c.59.cc.85
I am trying to convert "final mac" output to 288a.1c59.cc85. I think to do this we have to put "at mac" output to an array 1..2 3..4 5..6 concatenate and then use join function. Is there a better way to do this with in the join function itself, rather than first putting in a separate array
Re: Concatenate and join
by NetWallah (Canon) on Mar 31, 2016 at 03:33 UTC
|
This code produces the answer - you should be able to incorporate the idea into your code.
perl -e '@x=qw| 28 8a 1c 59 cc 85|;
my $o="";
for (my $i=0; $i<$#x; $i+=2){
$o.=$x[$i].$x[$i+1]."."}
chop $o;
print "$o\n"'
288a.1c59.cc85
Update: Fixed typo in code above, to produce right answer.
There are other, slightly more elegant methods (using natatime from List::MoreUtils), but to use those, you will need to use CPAN modules.
Here is another option (Has trailing "."):
perl -e '@x=qw| 28 8a 1c 59 cc 85|;
while ($_=shift @x){
print "$_" .shift (@x) . "."}'
Note -: This one destroys the source array.
This is not an optical illusion, it just looks like one.
| [reply] [d/l] [select] |
Re: Concatenate and join
by GotToBTru (Prior) on Mar 31, 2016 at 03:47 UTC
|
Because this method is destructive, I copy the @mac_add array before processing.
my @mac_add = qw/28 8a 1c 59 cc 85/;
my (@list,@parts);
@list = @mac_add;
while(@list) {
push @parts, join '', splice @list,0,2
}
my $mac_R5 = join '.',@parts;
But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)
| [reply] [d/l] [select] |
Re: Concatenate and join
by Cristoforo (Curate) on Mar 31, 2016 at 03:54 UTC
|
Another way using the transliteration operator. Assumes a 12 digit address.
my @outputlist = '28:8a:1c:59:cc:85';
for my $addr (@outputlist) {
my $mac_R5 = join ".", $addr =~ tr/://dr =~ /..../g;
print $mac_R5, "\n";
}
Update: Changed the transliteration to bind with the regex match. The former line was:
my $mac_R5 = join ".", $addr =~ tr/://d && $addr =~ /..../g;
Which works for perls before version 5.014. | [reply] [d/l] [select] |
Re: Concatenate and join
by choroba (Cardinal) on Mar 31, 2016 at 14:02 UTC
|
Another solution (TIMTOWTDI), using pack and unpack:
#!/usr/bin/perl
use warnings;
use strict;
my $mac_address = '28:8a:1c:59:cc:85';
$mac_address =~ tr/://d;
print join '.', unpack '(H4)*', pack 'H*', $mac_address;
Update: Could anyone use pack to skip the colons, without the need to remove them beforehand?
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
|
Interesting. I normally only think of pack and unpack in the context of working with binary buffers, which I seldom do in Perl.
While researching regex ideas, I did see your post at Re: Insert colons into a MAC address which is sort of similar to this problem, but I couldn't see how to apply it to leave off the final "." in my regex.
| [reply] |
|
It's not possible to use the same trick. You want to concatenate the two groups every time, but skip the dot sometimes. Maybe with eval:
s/(\w+):(\w+)(:?)/ $1 . $2 . '.' x !!$3 /ge;
or use two steps (which makes it similar to your solution):
s/(\w+):(\w+)/$1$2/g;
tr/:/./;
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord
}map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
| [reply] [d/l] [select] |
Re: Concatenate and join
by Marshall (Canon) on Mar 31, 2016 at 10:24 UTC
|
I think it is easier to calculate "final mac" directly from mac. I used a regex, but I couldn't figure out how to write it so that a final "." didn't appear at the end. I finally gave up and just ran another simple regex to ditch this unintended side effect at the end. I highly suspect that a more advanced regex could have avoided this, but sometimes straightforward is a good answer.
The intermediate atmac is not needed but is easy to calculate with tr. I'm not sure whether or not all 4 of these variants are needed? Or why atmac is in an array. But I figured that "final mac" was the most important.
Anyway another idea for you...
#!/usr/bin/perl
use warnings;
use strict;
my $mac = '28:8a:1c:59:cc:85';
(my $finalmac = $mac) =~ s/(\w+):(\w+)(:?)/$1$2./g;
$finalmac =~ s/.$//; #ditch "." at end
(my $atmac = $mac) =~ tr/:/ /;
print "mac = $mac\n";
print "atmac = $atmac\n";
print "final mac = $finalmac\n";
__END__
mac = 28:8a:1c:59:cc:85
atmac = 28 8a 1c 59 cc 85
final mac = 288a.1c59.cc85
Update: I just noticed the /o in your regex code. Modern Perl doesn't need this hint. I remember bench marking a lot of stuff years ago with Perl 5.10, and I didn't see any difference. Also see Perl regex documentation 5.22, " o - pretend to optimize your code, but actually introduce bugs". I would pay attention to a cautionary note like that! | [reply] [d/l] |
Re: Concatenate and join
by dbuckhal (Chaplain) on Mar 31, 2016 at 16:36 UTC
|
Given MAC-48 format, using either colons or hyphens, how about a substitution:
$ perl -le '$re = qr{(\S\S)[-:](\S\S)[-:](\S\S)[-:](\S\S)[-:](\S\S)[-:
+](\S\S)};
$str1 = "28:8a:1c:59:cc:85"; $str2 = "28-8a-1c-59-cc-85";
( $cat1 = $str1 )
=~ s/$re/$1$2.$3$4.$5$6/;
( $cat2 = $str2 )
=~ s/$re/$1$2.$3$4.$5$6/;
print "$str1 is now $cat1\n";
print "$str2 is now $cat2\n";
'
__output__
28:8a:1c:59:cc:85 is now 288a.1c59.cc85
28-8a-1c-59-cc-85 is now 288a.1c59.cc85
Too ugly?? | [reply] [d/l] |
|
| [reply] [d/l] [select] |
|
|