文本识别章节,分割

  • 一、思路
  • 二、文件上传
  • 三、文件分割
  • 四、正则识别章节标题
  • 五、获取章节标题行数
  • 六、根据章节行号分割文件
  • 七、入库、做记录
  • 因为项目有需求,整本小说上传之后自动识别章节目录,然后库存入库。所以就思考如何实际操作。

一、思路

  • 1,文件上传,这个基础了。另外,文件上传的大小,在php.ini可以设置,但是最后决定上传的大小的,是postmax的设置。

  • 2,获取文件,然后将其读取,若文件太大,就将其分割

  • 3,正则识别章节标题内容,然后记录下来

  • 4,将文件按行读取匹配章节标题,记录行数

  • 5,按章节标题行数-1,分割文件

  • 6,记录,入库,这样就能完整的得到整本小说的目录,和章节内容

二、文件上传

  • 因为框架自带的文件上传功能,他会把上传的文件按日期随意放置,这样不符合个人严谨的态度。所以就手写了个原生文件上传功能。
 /*** 原生上传文件* 根据上传的文件名判断文件在该路径是否已经上传*/public static function phpUpload($type,$path){//防止乱码header("Content-type: text/html; charset=utf-8");$file=$type;if ($_FILES[$file]['error']>0){    //file 是post上字段名return "Error:".$_FILES[$file]['error'];}//上传文件信息$data=['fileName'=>$fileNmae=$_FILES[$file]['name'],"type"=>$type=$_FILES[$file]['type'],'size'=>$size=($_FILES[$file]['size']/1024)."kb",'tmp_name'=>$tmp_name=$_FILES[$file]['tmp_name'],];$filepath=$path.DS.$fileNmae;           //文件路径,包含文件名$fileNmae=iconv('utf-8','gb2312',$fileNmae);if (self::fileIsHas($filepath))return null;   //判断文件是否已经上传if (!self::fileIsHas($path)) self::createdir($path);    //没有该文件夹则创建move_uploaded_file($tmp_name,$filepath);return $filepath;}
  • 还有一个filesHsa()函数,这个是判断文件是否存在的方法
  • 这方法没有判断文件上传类型、大小,可以根据个人情况添加

三、文件分割

  • 这里当初思考了两个方法,一个是将文件按规定大小分割,然后缓存起来,再每个读取,再合并。一个是,将文件分割,进行下面步骤,然后再读取。本文取用后者
  • 后来,发现PHP可以多线程,具体多线程可以看PHP多线程
  /*** 分段器* 默认每2m分段一次* filePath      文件路径* callback  回调函数,分割完文件,可以在回调函数中进行接下来步骤处理* blockSize 分割文件大小,默认是2m*/public static function sectionalizer($filePath,$callback,$blockSize=10485760 / 5){if (!is_callable($callback))return false;$size=filesize($filePath);  //整体大小while ($size>0){$residue=bcsub($size,$blockSize,0);$callbackSize=$residue>0?$residue:$size;$data=$callback()use($residue);    //回调函数,分段期间做的事$size=$residue;}return $data;}
  • 这个一个文件大小分割器,可以根据规定大小将文件分割,然后在回调函数中进行接下来步骤

四、正则识别章节标题

 /*** 获取整字符内容* @param $path*/public static function pregChapters(string $path,string $pattern,int $size){$file=fopen($path,'rb')or die("unable open the file");$content=fread($file,$size);fclose($file);//$pattern="/chapter[\s][A-Z]/i";preg_match_all($pattern,$content,$result,PREG_PATTERN_ORDER);return $result;}
  • 该方法可以根据正则获取文本内容
  • php的正则规则有些区别,具体可以看PHP正则
  • 可以根据上个分割器,将文本倒入分割

五、获取章节标题行数

  • 因为按章节标题分割需要获取具体章节标题行号
  /*** 返回章节对应的行数* @param $path* @param array $chapterName* @return array*/public static function ChaptersLine($path,array $chapterName){$fp=fopen($path,"rb");$lines=[];      //每一行$num=[];        //每一章节对应的行数while (!feof($fp)){$lines[]=fgets($fp);}$i=0;                                   //章节下标$chapterName=array_flip($chapterName);  //翻转数组,redis思想foreach ($lines as $k=> $line){if (empty($line))continue;if (isset($chapterName[trim($line)])){       //存在该下标,存在$i++;$num[]=['chapter_name'=>$lines[$k],'line_num'=>$k,'chapter_num'=>$i];}}fclose($fp);return $num;}
  • 当初是想把文本每一行,和章节标题数组进行遍历,但是这时间复杂度就为O(n)^2了
  • 所以就运用了redis、数据格式的思想
    • $chapterName[ ] 、array_flip 翻转过来
    • 在把文本每一行当作$chapterName[ ]数组的健,只要判断是否存在即可,时间复杂度为O(n)

六、根据章节行号分割文件

 /*** 分割章节* @param $path* @param $chapterNum* @param $novels_id* @throws \think\exception\DbException*/public static function splitByChapter($path,$chapterNum,$novels_id){$chapterPath=dirname($path).DS;$novels=Novels::get($novels_id);$chapterData=['novels_id'=>$novels_id,'title'=>$novels->title,'created_at'=>time(),];$i=0;$word_count=0;foreach ($chapterNum as $k =>$v){$endLine=$v['line_num']-1;$content=self::getLine($path,$i,$endLine);                                        //获取行,内容self::ChapterTxt($chapterPath.$v['chapter_num'].".txt",$content);       //生成章节文本$chapterData['word_count']=help::wordCount($content);                                         //字数统计$chapterData['num']=$v['chapter_num'];$chapterData['path']=NOVELS_PATH_MYSQL.$novels->title.DS.$v['chapter_num'].".txt";                 //章节目录路径,重组$chapter=Chapter::create($chapterData);                                                                  //入章节表$chapterManagerData=['chapter_num'=>$v['chapter_num'],'title'=>$chapterData['title'],'words_num'=>$chapterData['word_count'],'createtime'=>time(),];ChapterManage::create($chapterManagerData);                                             //后台章节列表页HandleRedis::getInstance()->chapterCache($novels_id.":".$chapter->getLastInsID(),json_encode($chapterData)); //种缓存$word_count+=$chapterData['word_count'];$i=$endLine;}return $word_count;}
  • 该方法是遍历章节数组,根据章节行数-1,分割文本,生成txt文件,然后做记录
 /*** 根据行数分割文件* @param $fileName* @param $start* @param $limit* @return string*/public static function getLine($fileName,$start,$limit){$f= new \SplFileObject($fileName,'r');$f->seek($start);   //文件指针指向行数$ret='';for ($i=0;$i<$limit;$i++){$ret.=$f->current();    //内容$f->next();             //下一行}return $ret;}
  • 该方法是根据文本行数,将文本进行分割,返回分割文本内容
/*** 生成章节文件* @param $chapterPath* @param $content* @return false|mixed*/public static function ChapterTxt($chapterPath,$content){if (help::fileIsHas($chapterPath))return false;$fp=fopen($chapterPath,'wb')or die(__("can't open this file :".$chapterPath));fwrite($fp,$content);fclose($fp);return $chapterPath;}
  • 该方法是根据文本内容生成txt文件导出,返回路径
  • txt文件导出,其实就是写入文件,若文件不存在则会新建
  • fopen中 wb 的b ,意思是window,和linux写入一致格式,不然会window文本放到linux系统会有文本内容win格式问题

七、入库、做记录

  • 整体调用总函数
 /*** 上传整本小说,分割章节,然后更新库* @param string $path* @param array $novels_id* @param string $patten* @throws \think\exception\DbException*/public static function wholeNovelsChapters(string $path,int $novels_id,string $patten="/chapter[\s][A-Z]+\./i"){/*$dir=novels_opeate::sectionalizer($path,function($size)use($path,$patten,$dir){$dir[]=novels_opeate::pregChapters($path,$patten,$size);    //分段将目录导入dir数组内return $dir;});*/$dir=novels_opeate::pregChapters($path,$patten,filesize($path))[0];                     //获取章节目录$chaptersNum=novels_opeate::ChaptersLine($path,$dir);                                   //获取章节目录所在的行数$word_count=novels_opeate::splitByChapter($path,$chaptersNum,$novels_id);                //分割整本书,生成章节txt文件,入库$chaptersNum=array_sum($chaptersNum);novels_model::where('id',$novels_id)                                                //更新小说表->update(['path'=>dirname($path).DS,'chapter_count'=>$chaptersNum,                                                  //小说章节总数'word_count'=>$word_count,]);unlink($path);                                                                          //删除原本}
  • 当初实现时候思维比较混乱,时间仓促没有使用分割器,后期可以优化
  • 其实用多线程的话,性能会大幅度提升,而且更加简便,后期有兴趣可以试试
  • 本文有个弊端,就是文本标题是正则选取,如果上传的文本章节标题和正则不相符,则会失去作用,所以需要提供具体章节标题
  • 本文使用的正则规则,“/chapter[\s][A-Z]+./i”,可以识别CHAPTER II.

文本识别标题后分割_php版相关推荐

  1. 【文本检测与识别白皮书-3.2】第一节:基于分割的场景文本识别方法

    3.2技术背景--文本识别方法 3.2.1 基于分割的场景文本识别方法 基于分割的识别算法是自然场景文本识别算法的一个重要分支(Wang 等,2012;Bissacco 等,2013;Jaderber ...

  2. diskgenius如何在Linux运行,DiskGenius能不能识别Linux的分割槽?笔记本上预装的Linux,用U盘启动PE后发现DiskGenius不能找到硬碟...

    DiskGenius能不能识别Linux的分割槽?笔记本上预装的Linux,用U盘启动PE后发现DiskGenius不能找到硬碟以下文字资料是由(历史新知网www.lishixinzhi.com)小编 ...

  3. MORAN文本识别算法开源,刷新多个OCR数据集state-of-the-art

    点击我爱计算机视觉标星,更快获取CVML新技术 近日华南理工大学金连文老师组在文本识别领域又出牛文,提出一种基于像素级不规则文本纠正的识别新算法MORAN(Multi-Object Rectified ...

  4. 腾讯优图10篇AAAI论文解析,涉及数学速算批改、视频识别和语义分割 | 附下载...

    点击上方↑↑↑"视学算法"关注我 来源:公众号 量子位 授权转 AI顶会AAAI开幕在即,入选论文悉数披露. 今日介绍10篇论文,来自腾讯旗下视觉研发平台腾讯优图,涉及数学速算批改 ...

  5. 网站面临改版!在修改标题后该如何快速提升排名?

    在网站优化中,网站标题的修改对网站的排名上升将有着很大的影响,一般网站不到迫不得已是不会轻易修改网站标题的.那么当面临改版后的网站,修改标题后该如何进行优化才能快速提升排名呢?下面一起来了解一下. 首 ...

  6. 怎样快速识别 英文地址中包含非英文字符_[论文笔记]端到端的场景文本识别算法--CRNN 论文笔记...

    本文大约 4000 字,阅读大约需要 10 分钟 论文地址:https://arxiv.org/abs/1507.05717 开源代码:https://github.com/bgshih/crnn 1 ...

  7. Mask TextSpotter v3 来了!最强端到端文本识别模型

    场景文本的识别可以用文本检测+文本识别两个过程来做,近年来端到端的场景文本识别(即Text Spotting)越来越引起学术界的重视,而华中科技大学白翔老师组的 Mask TextSpotter v1 ...

  8. 华科新开源文本识别算法:ASTER与DeepLesion数据集百度云下载

    (欢迎关注"我爱计算机视觉",一个有价值有深度的公众号~) ASTER 昨天跟大家介绍了白翔老师团队ECCV2018上的最新工作:华科白翔老师团队ECCV2018 OCR论文:Ma ...

  9. 用百度文字识别实现图片文本识别

    要用百度API则必须先注册百度开发者,然后才能使用百度的各项服务:地图API.文字语音转换API.文本识别API.....,文本识别的官方文档:文字识别-帮助与支持-百度云 注册完成后,需要用到以下三 ...

最新文章

  1. 标签选择器用于修改html元素默认的样式,html – 为什么CSS选择器与 sign(直接子)覆盖默认样式?...
  2. C语言 学生宿舍管理系统
  3. js 实现2的n次方计算函数_JS中数据结构与算法---排序算法
  4. 团队作业8----第二次项目冲刺(beta阶段)5.25
  5. 有了JSON.stringify(),处理json将变得更简单!!
  6. C/C++ ltoa函数 - C语言零基础入门教程
  7. /proc/sys/vm虚拟内存参数
  8. [转]bad interpreter:No such file or directory的原因
  9. 两组树形数据的比对_Python数据分析-可视化“大佬”之Seaborn
  10. Docker跨主机容器互传数据问题及解决方法
  11. 2018美赛D翻译从汽油驾驶到 E 驾驶( E 指电,而不是空)
  12. WIN7系统下Mapgis6.7常见的两个问题及解决办法
  13. 使用Origin绘制柱状图(入门)
  14. 1997年世界编程大赛一等奖作品(分享)
  15. 寻找那些神奇的自幂数---C语言
  16. Python入门程序
  17. NLP 自然语言处理实战
  18. c语言交通违章编程代码,C语言程序设计之交通处罚单管理系统报告(内含代码)...
  19. 新手如何快速入门Python(菜鸟必看篇)
  20. IBM服务器配置RAID5+热备教程

热门文章

  1. 1.2 行化简和阶梯形矩阵(线性代数及其应用-第5版-系列笔记)
  2. 华为海思麒麟搭载鸿蒙系统,华为P50曝光,99%屏占比+海思麒麟1020+鸿蒙系统,这才是华为...
  3. Win10找回windowsz照片查看器
  4. 自己动手写数据库:并发管理的基本原理
  5. js将数据存储到mysql_使用java读取js文件,将数据写入数据库
  6. 【通信】基于粒子群实现5G物联网云网络优化附matlab代码
  7. html在线播放音乐,HTML_the hot toddies_单曲在线试听_酷我音乐
  8. 火狐搜索栏打开新标签_使用SearchLoad选项修改Firefox的搜索栏行为
  9. python2安装pyyaml_python – 使用pip /添加PyYaml作为pip依赖来安装pyyaml
  10. 创客教育中的3D打印工具