2016-06-23 9 views
3

Я получил файл данных с мэйнфрейма. Я уже обработал преобразование EBCDIC в latin1 с PHP. Но теперь эти упакованные десятичные поля остались.Распаковать мэйнфрейм упакованную десятичную (BCD) с PHP

Для нелогич- числа 12345 упакована в 3 байта и выглядит следующим образом: x'12345C «

Отрицательный бы как: x'12345D»

Так правая половина Byte говорит знак. Есть ли способ сделать это легко с PHP?

Теперь я делаю это так:

$bin = "\x12\x34\x5C"; 
var_dump(
    unpack("H*", $bin) 
); 

Это приводит к:

array(1) { 
    [1]=> 
    string(4) "123c" 
} 

Теперь я могу проверить, если последний знак C или D и делать все вручную. Но, может быть, есть более приятное решение?

+4

Более приятное решение - заставить людей мэйнфрейма предоставить вам все «только текст». Затем вы можете выполнить преобразование кода на уровне файлов/записей и не иметь никаких проблем ни с чем. Это означает «отдельный знак», а также коэффициент масштабирования или фактическую десятичную точку, в зависимости от того, что вам будет легче.Если программа «Майнфрейм» не была закодирована в «Ассемблере», для них тривиально создавать такие данные, а затем экономить на вас. См. Также другие вопросы, помеченные упакованными десятичными знаками. –

+0

TL; DR «Мейнфрейм. Но, может быть, есть более приятное решение?» Да. Пусть вместо этого используют обработчики динозавров. –

+1

@Rhymoid ты имел в виду TS: DR? Там не выясняется. Нада. Нуль. Никто. Вам не нужно было придумывать интересные эпитеты, чтобы мы могли понять, что у вас трудности с чтением. Просто напиши что-нибудь. –

ответ

2

Как сказал Билл, заставить людей мэйнфрейма преобразовать файл в Текст на мейнфрейме и отправить текстовый файл, такие утилиты, как сортировка и т. Д., Могут сделать это на мэйнфрейме. Также есть ли только что упакованный десятичный номер в файл или у вас есть либо двоичный код, либо Zoned Decimal?

Если вы настаиваете делать это в PHP, вам нужно сделать упакованное десятичное преобразование перед тем вы делаете EBCDIC преобразование, потому что для уплотненного десятичной как x'400c « EBCDIC преобразователь будет выглядеть на х» 40 'и скажите, что это пространство и преобразовать его в x'20', поэтому ваш x'400c станет x'200c '.

Также окончательный nyble в Packed-decimal может быть f - без знака, а также c и d.

Наконец, если у вас есть Cobol прописи, мой проект JRecord имеет Cobol к Csv & & Cobol для конверсионных программ Xml (написано в Java). См

0

Хорошо, потому что я не нашел более хорошее решение, я сделал PHP-класс для обрабатывать записи из этого набора данных:

<?php 
namespace Mainframe; 

/** 
* Mainframe main function 
* 
* @author vp1zag4 
*   
*/ 
class Mainframe 
{ 

    /** 
    * Data string for reading 
    * 
    * @var string | null 
    */ 
    protected $data = null; 

    /** 
    * Default ouput charset 
    * 
    * @var string 
    */ 
    const OUTPUT_CHARSET = 'latin1'; 

    /** 
    * Record length of dataset 
    * 
    * @var integer 
    */ 
    protected $recordLength = 10; 

    /** 
    * Inits the 
    * 
    * @param unknown $data    
    */ 
    public function __construct($data = null) 
    { 
     if (! is_null($data)) { 
      $this->setData($data); 
     } 
    } 

    /** 
    * Sets the data string and validates 
    * 
    * @param unknown $data    
    * @throws \LengthException 
    */ 
    public function setData($data) 
    { 
     if (strlen($data) != $this->recordLength) { 
      throw new \LengthException('Given data does not fit to dataset record length'); 
     } 

     $this->data = $data; 
    } 

    /** 
    * Unpack packed decimal (BCD) from mainframe format to integer 
    * 
    * @param unknown $str    
    * @return number 
    */ 
    public static function unpackBCD($str) 
    { 
     $num = unpack('H*', $str); 
     $num = array_shift($num); 
     $sign = strtoupper(substr($num, - 1)); 
     $num = (int) substr($num, 0, - 1); 
     if ($sign == 'D') { 
      $num = $num * - 1; 
     } 
     return (int) $num; 
    } 

    /** 
    * convert EBCDIC to default output charset 
    * 
    * @param string $str    
    * @return string 
    */ 
    public static function conv($str, $optionalCharset = null) 
    { 
     $charset = (is_string($optionalCharset)) ? $optionalCharset : self::OUTPUT_CHARSET; 
     return iconv('IBM037', $charset, $str); 
    } 

    /** 
    * Reads part of data string and converts or unpacks 
    * 
    * @param integer $start 
    * @param integer $length 
    * @param bool $unpack 
    * @param bool | string $conv 
    */ 
    public function read($start, $length, $unpack = false, $conv = true) 
    { 
     if (empty($this->data)) { 
      return null; 
     } 

     $result = substr($this->data, $start, $length); 

     if($unpack) { 
      return self::unpackBCD($result); 
     } 

     if ($conv) { 
      return self::conv($result, $conv); 
     } 

     return $result; 
    } 
} 

С $ class-> read (1, 3, True) можно прочитать часть данных и конвертировать/распаковать ее в одно и то же время.

Возможно, это тоже поможет любому в любое время.

Но, конечно же, я попытаюсь настроить какой-то Job, который будет делать это для меня непосредственно на мэйнфрейме с некоторыми данными JSON в качестве вывода.

+1

Вам не хватает нескольких небольших лакомых кусочков - например, знак полубайта может быть другим значением, кроме 0xC и 0xD, и я не думаю, что вы правильно их обрабатываете. Вы можете просмотреть главу 8 в Принципах Операции (http://publibfp.dhe.ibm.com/epubs/pdf/dz9zr010.pdf) для всех подробностей о упакованных десятичных инструкциях. –

+0

Я представлял текстовые поля с фиксированной шириной. Если это нелегко для вашего языка, то Enterprise COBOL V6.1 имеет встроенную поддержку для генерации JSON, но V6.1 является довольно новым. Действительно, очень новое. Существует также системная служба для генерации JSON (это то, что использует компилятор COBOL). Он добавляет накладные расходы с обеих сторон, но если он лучше, чем вы можете обрабатывать поля символов фиксированной ширины, тогда это можно сделать. И да, @ValerieR верен. Вы вряд ли увидите других, кроме C, D или F, но что, если вы это сделаете? Поэтому вам нужно закодировать его, если вы собираетесь его кодировать, как указано выше. –

+0

Я не могу не думать, что его проще не делать ничего, но, возможно, это убивает ваш язык (кажется, проблема с C#, это просто не очень хорошо для многих полей фиксированной ширины, потому что это означает, что много строк обработка). –