我从大型机获得了一个数据文件。我已经用PHP处理了EBCDIC到latin1的转换。但是现在剩下这些压缩的十进制字段。
例如,数字12345被打包成3个字节,看起来像:x' 12345C'
否定将是:x' 12345D'
所以右半边的字节告诉了标志。有没有办法用PHP轻松完成这个?
现在我这样做:
$bin = "\x12\x34\x5C";
var_dump(
unpack("H*", $bin)
);
结果是:
array(1) {
[1]=>
string(4) "123c"
}
现在我可以检查最后一个标志是C还是D并且手动完成。但也许有更好的解决方案?
答案 0 :(得分:2)
正如Bill所说,让大型机人员将文件转换为大型机上的文本并发送文本文件,排序等实用程序可以在大型机上执行此操作。也是只是压缩十进制在文件中还是你有二进制或Zoned Decimal ???
如果您坚持在PHP中执行此操作,则需要在执行EBCDIC转换之前执行前的包装十进制转换,因为对于像x'400c这样的包装十进制 EBCDIC转换器将查看x'40'并说这是一个空格并将其转换为x'20',因此你的x'400c'变为x'200c'。
包装小数的最终nyble也可以是 f - 无符号以及c和d。
最后,如果你有Cobol Copybook,我的项目JRecord将Cobol改为Csv&& Cobol到Xml转换程序(用java编写)。参见
答案 1 :(得分: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-&gt; read(1,3,True),可以读取部分数据并同时转换/解压缩。
也许它会随时帮助任何人。
但是我当然会尝试设置一些Job,它将直接在大型机上以一些JSON数据作为输出为我做。