文本识别章节,分割

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

一、思路

  • 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. 浅谈 MVP in Android
  2. python条件语句-Python 条件语句
  3. VS2008 ,TFS2008破解序列号
  4. Qt把已有工程添加到其他工程中作为子工程或新创建子工程
  5. Docker - 安装并持久化PostgreSQL数据
  6. poj 1847 Tram 最短路 dijkstra、floyed
  7. kettle将文件路径定义为_Kettle变量和自己定义java代码的实例应用
  8. 如何设置程序默认“以管理员身份运行”
  9. 超分辨率谷歌卫星图下载经验贴
  10. 经方的魅力第二版》读书摘录
  11. coreutils8.32 hostid命令和源码分析
  12. imx6 Android gpu 内存,Use vivante GPU on IMX6 with 4.14 kernel
  13. ios 代码例子 卷边的翻书效果
  14. 【CuteJavaScript】GraphQL真香入门教程
  15. 使用Typora列表嵌套列表,回车无法返回上一级列表的状态
  16. 10年,从一个月薪2500的设备维修工,迫于压力转行,直到成为自动化测试专家···
  17. RK3288 EDP 调试
  18. PHP 多行文字内容的重复检测功能并统计重复次数
  19. syslog与syslog服务器的配置
  20. (已更新)最新打卡抽奖助手小程序源码,带微信通知功能,去授权

热门文章

  1. 安卓屏幕朗读app_你们要的小说App来了,永久免费不要钱,书源全网最全
  2. 美团点评开源 SQL 优化工具 SQLAdvisor 测试报告
  3. Matlab中十字线出不来,如何在MATLAB中实现已弃用的完整十字线指针功能?
  4. 20180125 high cohesive low coupling
  5. python词云是什么意思_python-词云
  6. 精密压接之曲柄连杆模型计算(含MATLAB仿真+博途SCL源代码)
  7. 【备忘】【No2】2016年最新云计算视频教程hadoop大数据实战开发
  8. 企业的Windows活动目录规划方案集合(附学习视频)
  9. 3DMax教程 教你在3DMax中怎么渲染黑色的描边 渲染黑色的描边有三种方法:
  10. java 写文件 0x0d_Java的文件读写操作 转