Jul
20
2018
【原创】PHP纯文本制表
有个打印机的项目让小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
发表评论: