【原创】PHP纯文本制表

作者Veris 文章分类 分类:PHP 文章评论 0条评论 阅读次数 已被围观 1154

有个打印机的项目让小V比较头疼:需要打印一个表格,原先是使用ESC/POS指令实现的,但是不同打印机会有兼容性问题,所以小V想自己写一个纯文本的表格,直接打印表格数据以此避免兼容问题,小V昨晚想着想着研究写到两点左右,2333,在此把一些代码分享出来,供广大网友参考!

<?php
/**
 * PHP纯文本制表
 * @author Veris
 * @blog http://www.mostclan.com
 * @date 2018.07.20
 */

/**
 * 获取打印字符串长度
 * @param  string $str 待计算字符串
 * @return integer     长度
 */
function get_printstr_len($str) {
	if($str===''){
		return 0;
	}
    $len=0;
    $arr=preg_split('/(?<!^)(?!$)/u', $str );
    foreach($arr as $v){
        if(strlen($v)==3){
            $len+=2;
        }else{
            $len++;
        }
    }
    return $len;
}

// $content='<table:16,24><tr><td>品名</td><td>数量</td><td>单价</td></tr><tr><td>宫保鸡丁</td><td>x5</td><td>0.01</td></tr><tr><td>爆炒猪肝(不要葱、不要辣椒,少放盐!!!!!)</td><td>x3</td><td>29.99</td></tr></table>';
$content=isset($_POST['content'])?$_POST['content']:'';

// 排版模式
$mode=isset($_POST['mode'])?$_POST['mode']:'default';
// 打印机最大打印位数
$bit=isset($_POST['bit'])?$_POST['bit']:32;
// 行间距
$padding=isset($_POST['padding'])?$_POST['padding']:0;
// 列间距
$spacing=isset($_POST['spacing'])?$_POST['spacing']:1;

// 匹配制表
preg_match_all('/<table:(?<table>.*?)<\/table>/',$content,$tableArr);
foreach($tableArr['table'] as $tableKey => $table)
{
	$tableData=[];
	// 获取制表点
	$posArr=[];
	$posSplit=strpos($table,'>');
	if($posSplit!==false)
	{
		$posArr=explode(',',substr($table,0,$posSplit));
		array_unshift($posArr,1);
		$posArr=array_unique($posArr);
		// 制表点排序
		sort($posArr);
		// 检查制表点合法性(每个制表点最少4位字符长度)
		$posLeg=true;
		foreach($posArr as $key => $pos)
		{
			if(isset($posArr[$key+1]))
			{
				if($posArr[$key+1]-$pos<4)
				{
					$posLeg=false;
					break;
				}
			}
		}
		// 制表点不合法
		if($posLeg==false){
			continue;
		}
	}
	// 列数
	$column=count($posArr);
	// 最多支持制表点
	if($column>=$bit/4){
		continue;
	}

	// 匹配行
	preg_match_all('/<tr>(?<tr>.*?)<\/tr>/',$table,$trArr);
	foreach($trArr['tr'] as $tr)
	{
		// 匹配列
		$tdData=[];
		// 各列折行数组
		$foldArr=[];
		// 各列折行文本
		$foldTextArr=[];
		preg_match_all('/<td>(?<td>.*?)<\/td>/',$tr,$tdArr);
		for($tdKey=0; $tdKey<$column; $tdKey++)
		{
			if(!isset($tdArr['td'][$tdKey])){
				$tdData[$tdKey]='';
				continue;
			}
			$td=$tdArr['td'][$tdKey];
			$n=get_printstr_len($td);
			// 位差
			$bitDiff=isset($posArr[$tdKey+1])?$posArr[$tdKey+1]-$posArr[$tdKey]:$bit-$posArr[$tdKey];
			$bitDiff=$bitDiff>$spacing?$bitDiff-$spacing:1;

                        // 首列独行模式
                        if($n>$bitDiff && $mode=='FSAL'){
                            if($tdKey==0){
                                $tdData[0]=$td;
                                $tdData[0]='';
                                $tableData[][0]=$td;
                                // 新行
                                // $tableData[]=[];
                                continue;
                            }
                        }

			// 获取折行数据
			if($foldArr[]=(int)ceil($n/$bitDiff))
			{
			    $len=0;
				$i=0;
				$foldText=[];
			    $arr=preg_split('/(?<!^)(?!$)/u', $td);
			    foreach($arr as $v){
					$len+=strlen($v)==3?2:1;
					if($len<=$bitDiff){
						if(!isset($foldText[$i])){
							$foldText[$i]=$v;
						}else{
							$foldText[$i].=$v;
						}
					}else{
						$foldText[++$i]=$v;
						$len-=$bitDiff;
					}
			    }
				$tdData[$tdKey]=array_shift($foldText);
				$foldTextArr[$tdKey]=$foldText;
			}else{
				$tdData[$tdKey]=$td;
			}
		}
		$tableData[]=$tdData;
		// 最大增加行数(-1去掉首行)
		$maxFold=max($foldArr)-1+$padding;
		// 补充折行数据
		for($i=0; $i<$maxFold; $i++)
		{
			$foldTdData=[];
			for($j=0; $j<$column; $j++)
			{
				$foldTdData[$j]=isset($foldTextArr[$j][$i])?$foldTextArr[$j][$i]:'';
			}
			$tableData[]=$foldTdData;
		}
	}
	// var_dump($tableData);
	// 渲染数据
	$tableRender='';
	foreach($tableData as $tr)
	{
		$trStr='';
		foreach($tr as $key => $td)
		{
			// 位差
			$bitDiff=isset($posArr[$key+1])?$posArr[$key+1]-$posArr[$key]:$bit-$posArr[$key];
			$tdLen=get_printstr_len($td);
			$padNum=$bitDiff-$tdLen;
			$pad=$padNum>0?str_repeat(' ',$padNum):'';
			$trStr.=$td.$pad;
		}
		// var_dump($trStr);
		$tableRender.=$trStr.PHP_EOL;
	}
	// echo $tableRender;
	$content=str_replace($tableArr[0][$tableKey],$tableRender,$content);
}
echo '<hr>';
echo '<pre>';
echo $content;


附上DEMO测试地址:http://www.mostclan.com/demo/text-table.php

分类:PHP
标签: 纯文本制表

发表评论: