http://www.perlmonks.org?node_id=947757

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

Hi monks,

I'm searching a way to insert colons into a mac address in the format:

525400eb8b36

to get:

52:54:00:eb:8b:36

one way is this:

$mac = join(":", /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);

but it's _very_ ugly.

This also works: $mac = join(':', unpack('A2A2A2A2A2A2', $_));

but I would prefer a regex; is there a way to make the regex above more compact?

How would you perform this tasK?

Thanks,
bye.

Replies are listed 'Best First'.
Re: Insert colons into a MAC address
by choroba (Cardinal) on Jan 13, 2012 at 15:12 UTC
    Using look-ahead not to insert final colon:
    $mac =~ s/(..)(?=.)/$1:/g
Re: Insert colons into a MAC address
by hbm (Hermit) on Jan 13, 2012 at 16:00 UTC

      Without nasty look-aheadses:

      >perl -wMstrict -le "my $ma = '525400eb8b36'; $ma =~ s/..\K\B/:/g; print qq{'$ma'}; " '52:54:00:eb:8b:36'
        >perl -wMstrict -le 'my $ma="525400eb8b36"; $ma =~ s/..\K\B/:/g; > print $ma; ' Unrecognized escape \K passed through at -e line 1. 525400eb8b36 >
        Old Perl Version syndrome, I guess.
Re: Insert colons into a MAC address
by johngg (Canon) on Jan 13, 2012 at 16:15 UTC

    A less succinct substr approach.

    knoppix@Microknoppix:~$ perl -E ' > $mac = q{525400eb8b36}; > substr $mac, $_, 0, q{:} > for reverse grep { ! ( $_ % 2 ) } 2 .. 10; > say $mac;' 52:54:00:eb:8b:36 knoppix@Microknoppix:~$

    Cheers,

    JohnGG

Re: Insert colons into a MAC address
by tobyink (Canon) on Jan 13, 2012 at 17:23 UTC

    If you want to keep using a regexp, then:

    $mac =~ s/^(..)(..)(..)(..)(..)(..)$/$1:$2:$3:$4:$5:$6/ if $mac =~ /^[0-9A-F]{12}$/i;
      Instead of using the [0-9A-F] character class (more correct would be [0-9a-fA-F] and then you can drop the i parameter) you can use \p{Hex}.

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Insert colons into a MAC address
by Not_a_Number (Prior) on Jan 13, 2012 at 23:30 UTC
    but I would prefer a regex

    Any particular reason? If you're thinking of input validation, how about:

    $_ = '525400eb8b36'; die "Invalid input\n" if length != 12 or /[^[:xdigit:]]/; print join ':', unpack '(A2)*';

    Alternatively, use a CPAN module:

    use Net::MAC; print Net::MAC->new( mac => '525400eb8b36' )->as_Sun();

      I remember when I used to think why on earth would I use a whole module if I'm just doing this one thing that can clearly be done using the built-in features of Perl. Boy, was I an idiot.


      $,=qq.\n.;print q.\/\/____\/.,q./\ \ / / \\.,q.    /_/__.,q..
      Happy, sober, smart: pick two.
        Well, I think I'll choose this:

        $mac =~ s/([0-9a-fA-F]{2})\B/$1:/g;

        which can be also spelled as:

        $mac =~ s/(\p{Hex}{2})\B/$1:/g;

        The [:xdigit:] class does not work (I don't know why).

        @Not_a_Number: probably there isn't a reason to prefer a regex over 'unpack' or the use of a module, in this case, since this regex is not really more readable than other methods.
        Anyway I'm more familiar with regexes than with unpack or the Net::MAC module, so there is a chanche that I will recognize and understand that sooner when looking again at my code in the future.
        As for modules, I often avoid (or completely overlook) them, because I usually have little or no control on the systems I work onto (so installing a module can be a tricky or impossible task). I see that "use a module" vs "reinvent the wheel" is an ever discussed problem. I'm on the "reinvent the wheel" side, but it's not my fault :)

        Thanks to all, bye.

        Edit:
        jut in case someone come here in the future.

        [:xdigit:]

        actually works:

        $mac =~ s/([[:xdigit:]]{2})\B/$1:/g;

        I just didn't put enough square brackets. [:xdigit:] is equivalent to [:xdigt] (literally), while [[:xdigit:]] is equivalent to [0-9a-fA-F]. Reading the f. manual helps as usual :)
Re: Insert colons into a MAC address
by JavaFan (Canon) on Jan 15, 2012 at 03:05 UTC
Re: Insert colons into a MAC address
by Anonymous Monk on Jan 15, 2012 at 03:36 UTC
    $mac = join(':', unpack('A2A2A2A2A2A2', $_));

    Could be written as:

    $mac = join(':', unpack '(A2)*', $_);