Posted 2022-02-02 with tags overpunch, PHP, data formats

Signed overpunch is a format used to store the positive or negative sign of a number without using a “+” or “-“ character by changing the last digit. Frequently used in fixed-width format text files to prevent the spacing from being changed due to the addition of a plus or minus sign.

Example field description: S9(6)V99

  • S - Leading sign
  • 9(5) - 6 decimal digits
  • V - Implied decimal point
  • 99 - 2 digits after the implied decimal point

Implemented in PHP (could probably be done more elegantly):

function parse_overpunch($data, $digitsAfterDecimal=2){

    $last = substr($data, -1);
    $negative = array_search($last, ['{','A','B','C','D','E','F','G','H','I']) === false;

    switch ($last) {
        case '{': $data = substr_replace($data, 0, -1); break;
        case 'A': $data = substr_replace($data, 1, -1); break;
        case 'B': $data = substr_replace($data, 2, -1); break;
        case 'C': $data = substr_replace($data, 3, -1); break;
        case 'D': $data = substr_replace($data, 4, -1); break;
        case 'E': $data = substr_replace($data, 5, -1); break;
        case 'F': $data = substr_replace($data, 6, -1); break;
        case 'G': $data = substr_replace($data, 7, -1); break;
        case 'H': $data = substr_replace($data, 8, -1); break;
        case 'I': $data = substr_replace($data, 9, -1); break;
        case '}': $data = substr_replace($data, 0, -1); break;
        case 'J': $data = substr_replace($data, 1, -1); break;
        case 'K': $data = substr_replace($data, 2, -1); break;
        case 'L': $data = substr_replace($data, 3, -1); break;
        case 'M': $data = substr_replace($data, 4, -1); break;
        case 'N': $data = substr_replace($data, 5, -1); break;
        case 'O': $data = substr_replace($data, 6, -1); break;
        case 'P': $data = substr_replace($data, 7, -1); break;
        case 'Q': $data = substr_replace($data, 8, -1); break;
        case 'R': $data = substr_replace($data, 9, -1); break;
        default: break;
    }

    // ex. "000000000" after swapping in overpunch digit
    if($data == 0){
        return 0;
    }

    $data = substr_replace($data, '.', -$digitsAfterDecimal, 0);

    return $negative ? -$data : ltrim($data, '0');
}