Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Concatenate and join

by Anonymous Monk
on Mar 31, 2016 at 03:08 UTC ( #1159176=perlquestion: print w/replies, xml ) Need Help??

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 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

Replies are listed 'Best First'.
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.

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)

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.

Re: Concatenate and join
by choroba (Archbishop) 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,
      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.

        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,
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!
Re: Concatenate and join
by dbuckhal (Hermit) 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??

      Dunno if this is too/more/less ugly, but anyway...


      Give a man a fish:  <%-{-{-{-<

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1159176]
Approved by Paladin
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2022-05-16 05:51 GMT
Find Nodes?
    Voting Booth?
    Do you prefer to work remotely?

    Results (62 votes). Check out past polls.