Old question name: How to effectively split a binary string in a groups of 10, 0, 11?
I have some strings as an input, which are binary representation of a number. For example:
10011
100111
0111111
11111011101
I need to split these strings (or arrays) into groups of 10, 0, and 11 in order to replace them.
10 => 11
0 => 0
11 => 10
How to do it? I have tried these options but don't work.
preg_match('/([10]{2})(0{1})([11]{2})/', $S, $matches);
It should be [10] [0], [11] for 10011 input. And it should be 11010 when replaced.
UPD1.
Actually, I'm trying to do a negation algorithm for converting a positive number in a base -2 to a negative one in a base -2. It could be done with an algorithm from Wikipedia with a loop. But byte groups replacing is a much faster. I have implemented it already and just trying to optimize it.
For this case 0111111
it's possible to add 0 in the end. Then rules will be applied. And we could remove leading zeros in a result. The output will be 101010.
UPD2.
@Wiktor Stribiżew proposed an idea how to do a replace immediately, without splitting bytes into groups first. But I have a faster solution already.
$S = strtr($S, $rules);
The meaning of this question isn't do a replacement, but get an array of desired groups [11] [0] [10].
UPD3.
This is a solution which I reached with an idea of converting binary groups. It's faster than one with a loop.
function solution2($A)
{
$S = implode('', $A);
//we could add leading 0
if (substr($S, strlen($S) - 1, 1) == 1) {
$S .= '0';
}
$rules = [
'10' => '11',
'0' => '0',
'11' => '10',
];
$S = strtr($S, $rules);
$arr = str_split($S);
//remove leading 0
while ($arr[count($arr) - 1] == 0) {
array_pop($arr);
}
return $arr;
}
But the solution in @Alex Blex answer is faster.
Answering the question
algorithm for converting a positive number in a base -2 to a negative one in a base -2
I believe following function is more efficient than a regex:
function negate($negabin)
{
$mask = 0xAAAAAAAAAAAAAAA;
return decbin((($mask<<1)-($mask^bindec($negabin)))^$mask);
}
Parameter is a positive int60 in a base -2 notation, e.g. 11111011101.
The function converts the parameter to base 10, negate it, and convert it back to base -2 as described in the wiki: https://en.wikipedia.org/wiki/Negative_base#To_negabinary
Works on 64bit system, but can easily adopted to work on 32bit.