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

The problem I face is this:
I have a string consisting of 15 hex characters. I need to manipulate the string thus:
orig. string = "0102030405060A0BC"<br> new. str = "102030405060A0B0FC"<br>
where the F is a arbitrary character. The strings are just examples and could consist of any combination of hex characters
My question is - what is the most elegant way of doing this?

Replies are listed 'Best First'.
Re: Rearranging a string
by lhoward (Vicar) on Jul 03, 2000 at 18:58 UTC
    Based on your example, I am unsure of exactly the manipulation you ar trying to perform. In general most string reordering type manipulations are best accomplished with the substr function.
    my $origstr="0102030405060A0BC"; my $newstr=substr($origstr,1,15).substr($origstr,0,1)."F".substr($orig +str,16,1);
Re: Rearranging a string
by ZZamboni (Curate) on Jul 03, 2000 at 18:56 UTC
    In this case, it might help if you describe what you want to do instead of only giving an example. Here's what I gather: shift the first 16 characters to the left, with wraparound, and insert F between them and the next character. Here's how I would do that:
    $s=~s/^(.)(.{15})/$2$1F/;

    --ZZamboni

(jeffa) Re: Rearranging a string
by jeffa (Bishop) on Jul 03, 2000 at 20:01 UTC
    I see the pattern that muppetBoy is looking for ... but my solution is not particularly elegant.

    The pattern is to pop off two bytes, reverse them, and then append them to a new string. If only one byte is left at the end, prepend an 'F' to it, and append that combination.

    My clunky solution that is beggin' to be improved upon:

    my @bytes = split (/([0-9A-F]{2})/, "0102030405060A0BC"); my $new; foreach (@bytes) { next if $_ eq ''; $new .= (length($_)==2) ? reverse($_) : 'F' . $_; } print $new, "\n";
    I thought I knew split well enough, but apparently not as the @bytes array has empty elements in it (hence the hack to check if $_ is empty).
      If this is the case, another way of doing it would be:
      $s='0102030405060A0BC' # Fix to even number of chars $s.=(length($s)%2?"F":"") for($i=0; $i<length($s); $i+=2) { substr($s,$i,2)=reverse(substr($s,$i,2)); }
      jeffa: you were getting empty elements because the two-character pairs are being used as delimiters, with empty elements between them.

      --ZZamboni

      The reason you are getting empty elements in @bytes is because there is nothing in between your delimiters (i.e. 01 and 02 are both delimiters and there is nothing between them). For a simpler example of this behavior, examine split(/x/, 'xxxxxxxxC') and split(/(x)/, 'xxxxxxxxC')
Re: Rearranging a string
by maverick (Curate) on Jul 04, 2000 at 03:18 UTC
    Does this do what you need?
    $string = '0102030405060A0BC'; $fill_char = '0'; if (length($string) % 2 != 0) { $string .= $fill_char; } @bytes = split(//,$string); for ($i=0; $i <= $#bytes; $i+=2) { print $bytes[$i+1]; print $bytes[$i]; } print "\n";
    /\/\averick
Re: Rearranging a string
by chromatic (Archbishop) on Jul 04, 2000 at 03:35 UTC
    A regex will do it, if you're careful:
    $old .= (length($old) % 2) ? 'F' : ''; $old =~ s/\G(\w)(\w)/$2$1/g;
    Note that \w includes letters, digits, and the underscore character. If the latter isn't acceptable, use a character class.
Re: Rearranging a string
by muppetBoy (Pilgrim) on Jul 04, 2000 at 11:42 UTC
    Thanks to all those that made the effort to help.
    I posted the question in a bit of a hurry yesterday and consequently it may not have been as clear as I intended - my apologies. Thanks to jeffa for explaining it a bit more precisely.