在二进制字符串的开头插入 x 位

问题描述 投票:0回答:1

我有一个函数,可以在二进制字符串的开头插入值为 0 的 x 位,并将所有现有位右移。 这适用于除最后一个之外的所有测试用例:1000 0000 (0x80) 变为 0100 0000 (0x40)

这对于第一个字节是正确的,但是通过将最后一位向右移动,必须创建一个新字节: 0100 0000 0000 0000 (0x40 0x00)

我如何将我的功能扩展到这种特殊情况,并且我是否忽略了其他任何事情?


function insertBitsLeft($binaryString, $numBits) {
    if (!is_numeric($numBits) || $numBits <= 0) {
        return $binaryString;
    }

    // Calculate the number of bytes that can be added at the beginning
    $numBytes = intdiv($numBits, 8);

    // Calculate the remainder (overflow/rest)
    $remainder = $numBits % 8;

    // Add the bytes with a bit value of 0 at the beginning
    $newBinaryString = str_repeat("\x00", $numBytes);

    // Add the overflow/rest by shifting the remaining bits
    if ($remainder > 0 && strlen($binaryString) > 0) {
        $shiftedBits = 0;
        for ($i = 0; $i < strlen($binaryString); $i++) {
            $currentByte = ord($binaryString[$i]);
            $newBinaryString .= chr(($currentByte >> $remainder) | $shiftedBits);
            $shiftedBits = ($currentByte << (8 - $remainder)) & 0xFF;
        }
        if ($shiftedBits > 0) {
            $newBinaryString .= chr($shiftedBits);
        }
    } else {
        if ($numBytes == 0) {
            $newBinaryString = str_repeat("\x00", 1);
        } else if (strlen($newBinaryString) > 0 && $remainder > 0) {
            $newBinaryString .= str_repeat("\x00", 1);
        }

        $newBinaryString .= $binaryString;
    }

    return $newBinaryString;
}

$testCases = [
    // Test Case 1: Normal case, $binaryString is not empty, $numBits = 16
    [
        "input" => ["binaryString" => "\xFF\xFF", "numBits" => 16],
        "expected" => "\x00\x00\xFF\xFF",
        "description" => "Adds 2 zero bytes at the beginning."
    ],
    // Test Case 2: $binaryString is empty, $numBits = 8
    [
        "input" => ["binaryString" => "", "numBits" => 8],
        "expected" => "\x00",
        "description" => "Adds a zero byte when binaryString is empty and numBits = 8."
    ],
    // Test Case 3: $binaryString is empty, $numBits < 8
    [
        "input" => ["binaryString" => "", "numBits" => 5],
        "expected" => "\x00",
        "description" => "Adds a zero byte when binaryString is empty and numBits < 8."
    ],
    // Test Case 4: $binaryString is not empty, $numBits = 7 (remainder)
    [
        "input" => ["binaryString" => "\xFF", "numBits" => 7],
        "expected" => "\x01\xFE",
        "description" => "Adds 7 zero bits and shifts the existing byte by 7 bits."
    ],
    // Test Case 5: $binaryString is empty, $numBits = 0
    [
        "input" => ["binaryString" => "", "numBits" => 0],
        "expected" => "",
        "description" => "Returns an empty string when numBits = 0."
    ],
    // Test Case 6: $binaryString is not empty, $numBits = 0
    [
        "input" => ["binaryString" => "\xAA", "numBits" => 0],
        "expected" => "\xAA",
        "description" => "Returns the original string when numBits = 0."
    ],
    // Test Case 7: $binaryString is not empty, $numBits = 3
    [
        "input" => ["binaryString" => "\xA3", "numBits" => 3],
        "expected" => "\x14\x60",
        "description" => "Adds 3 zero bits and shifts the existing byte by 3 bits."
    ],
    // Test Case 8: $binaryString is not empty, $numBits > length of $binaryString
    [
        "input" => ["binaryString" => "\xAA\xBB", "numBits" => 20],
        "expected" => "\x00\x00\x0A\xAB\xB0",
        "description" => "Adds 20 bits, shifting the last bits of the original string."
    ],
    // Test Case 9: $numBits is negative
    [
        "input" => ["binaryString" => "\xAA", "numBits" => -5],
        "expected" => "\xAA",
        "description" => "Returns the original string when numBits is negative."
    ],
    // Test Case 10: $numBits is not numeric
    [
        "input" => ["binaryString" => "\xAA", "numBits" => "foo"],
        "expected" => "\xAA",
        "description" => "Returns the original string when numBits is not numeric."
    ],
    // Test Case 11: $binaryString is not empty, $numBits = 1
    [
        "input" => ["binaryString" => "\x80", "numBits" => 1],
        "expected" => "\x40\x00",
        "description" => "Shifts the most significant bit of a byte."
    ],
];

foreach ($testCases as $case) {
    $result = insertBitsLeft($case["input"]["binaryString"], $case["input"]["numBits"]);
    if ($result === $case["expected"]) {
        echo "PASS: " . $case["description"] . "\n";
    } else {
        echo "FAIL: " . $case["description"] . "\n";
        echo "Expected: " . bin2hex($case["expected"]) . "\n";
        echo "Got:      " . bin2hex($result) . "\n";
    }
}

php
1个回答
0
投票

代码中的问题是由于未正确处理边缘情况而引起的,在这种情况下,需要移动位,从而在末尾需要一个额外的字节。要正确管理这种情况,请按照以下步骤操作:

  1. 为 $numBytes 添加填充字节。
  2. 通过移位每个字节并将结转位传播到下一个字节来处理剩余位。
  3. 如果超出当前字节大小,则在末尾附加任何结转位。

这是更正后的函数:


function insertBitsLeft($binaryString, $numBits) {
    if (!is_numeric($numBits) || $numBits <= 0) {
        return $binaryString;
    }

    $numBytes = intdiv($numBits, 8);
    $remainder = $numBits % 8;

    $newBinaryString = str_repeat("\x00", $numBytes);

    if ($remainder > 0 && strlen($binaryString) > 0) {
        $shiftedBits = 0;
        for ($i = 0; $i < strlen($binaryString); $i++) {
            $currentByte = ord($binaryString[$i]);
            $newByte = ($currentByte >> $remainder) | $shiftedBits;
            $newBinaryString .= chr($newByte);
            $shiftedBits = ($currentByte << (8 - $remainder)) & 0xFF;
        }
        if ($shiftedBits > 0) {
            $newBinaryString .= chr($shiftedBits);
        }
    } else {
        $newBinaryString .= $binaryString;
    }

    return $newBinaryString;
}

$testCases = [
    [
        "input" => ["binaryString" => "\xFF\xFF", "numBits" => 16],
        "expected" => "\x00\x00\xFF\xFF",
        "description" => "Adds 2 zero bytes at the beginning."
    ],
    [
        "input" => ["binaryString" => "", "numBits" => 8],
        "expected" => "\x00",
        "description" => "Adds a zero byte when binaryString is empty and numBits = 8."
    ],
    [
        "input" => ["binaryString" => "", "numBits" => 5],
        "expected" => "\x00",
        "description" => "Adds a zero byte when binaryString is empty and numBits < 8."
    ],
    [
        "input" => ["binaryString" => "\xFF", "numBits" => 7],
        "expected" => "\x01\xFE",
        "description" => "Adds 7 zero bits and shifts the existing byte by 7 bits."
    ],
    [
        "input" => ["binaryString" => "", "numBits" => 0],
        "expected" => "",
        "description" => "Returns an empty string when numBits = 0."
    ],
    [
        "input" => ["binaryString" => "\xAA", "numBits" => 0],
        "expected" => "\xAA",
        "description" => "Returns the original string when numBits = 0."
    ],
    [
        "input" => ["binaryString" => "\xA3", "numBits" => 3],
        "expected" => "\x14\x60",
        "description" => "Adds 3 zero bits and shifts the existing byte by 3 bits."
    ],
    [
        "input" => ["binaryString" => "\xAA\xBB", "numBits" => 20],
        "expected" => "\x00\x00\x0A\xAB\xB0",
        "description" => "Adds 20 bits, shifting the last bits of the original string."
    ],
    [
        "input" => ["binaryString" => "\xAA", "numBits" => -5],
        "expected" => "\xAA",
        "description" => "Returns the original string when numBits is negative."
    ],
    [
        "input" => ["binaryString" => "\xAA", "numBits" => "foo"],
        "expected" => "\xAA",
        "description" => "Returns the original string when numBits is not numeric."
    ],
    [
        "input" => ["binaryString" => "\x80", "numBits" => 1],
        "expected" => "\x40\x00",
        "description" => "Shifts the most significant bit of a byte."
    ],
];

foreach ($testCases as $case) {
    $result = insertBitsLeft($case["input"]["binaryString"], $case["input"]["numBits"]);
    if ($result === $case["expected"]) {
        echo "PASS: " . $case["description"] . "\n";
    } else {
        echo "FAIL: " . $case["description"] . "\n";
        echo "Expected: " . bin2hex($case["expected"]) . "\n";
        echo "Got:      " . bin2hex($result) . "\n";
    }
}

此修订后的函数确保任何必要的位携带都会适当地生成附加字节,并处理测试用例指定的所有情况。

© www.soinside.com 2019 - 2024. All rights reserved.