文本识别标题后分割_php版
文本识别章节,分割
- 一、思路
- 二、文件上传
- 三、文件分割
- 四、正则识别章节标题
- 五、获取章节标题行数
- 六、根据章节行号分割文件
- 七、入库、做记录
- 因为项目有需求,整本小说上传之后自动识别章节目录,然后库存入库。所以就思考如何实际操作。
一、思路
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版相关推荐
- 【文本检测与识别白皮书-3.2】第一节:基于分割的场景文本识别方法
3.2技术背景--文本识别方法 3.2.1 基于分割的场景文本识别方法 基于分割的识别算法是自然场景文本识别算法的一个重要分支(Wang 等,2012;Bissacco 等,2013;Jaderber ...
- diskgenius如何在Linux运行,DiskGenius能不能识别Linux的分割槽?笔记本上预装的Linux,用U盘启动PE后发现DiskGenius不能找到硬碟...
DiskGenius能不能识别Linux的分割槽?笔记本上预装的Linux,用U盘启动PE后发现DiskGenius不能找到硬碟以下文字资料是由(历史新知网www.lishixinzhi.com)小编 ...
- MORAN文本识别算法开源,刷新多个OCR数据集state-of-the-art
点击我爱计算机视觉标星,更快获取CVML新技术 近日华南理工大学金连文老师组在文本识别领域又出牛文,提出一种基于像素级不规则文本纠正的识别新算法MORAN(Multi-Object Rectified ...
- 腾讯优图10篇AAAI论文解析,涉及数学速算批改、视频识别和语义分割 | 附下载...
点击上方↑↑↑"视学算法"关注我 来源:公众号 量子位 授权转 AI顶会AAAI开幕在即,入选论文悉数披露. 今日介绍10篇论文,来自腾讯旗下视觉研发平台腾讯优图,涉及数学速算批改 ...
- 网站面临改版!在修改标题后该如何快速提升排名?
在网站优化中,网站标题的修改对网站的排名上升将有着很大的影响,一般网站不到迫不得已是不会轻易修改网站标题的.那么当面临改版后的网站,修改标题后该如何进行优化才能快速提升排名呢?下面一起来了解一下. 首 ...
- 怎样快速识别 英文地址中包含非英文字符_[论文笔记]端到端的场景文本识别算法--CRNN 论文笔记...
本文大约 4000 字,阅读大约需要 10 分钟 论文地址:https://arxiv.org/abs/1507.05717 开源代码:https://github.com/bgshih/crnn 1 ...
- Mask TextSpotter v3 来了!最强端到端文本识别模型
场景文本的识别可以用文本检测+文本识别两个过程来做,近年来端到端的场景文本识别(即Text Spotting)越来越引起学术界的重视,而华中科技大学白翔老师组的 Mask TextSpotter v1 ...
- 华科新开源文本识别算法:ASTER与DeepLesion数据集百度云下载
(欢迎关注"我爱计算机视觉",一个有价值有深度的公众号~) ASTER 昨天跟大家介绍了白翔老师团队ECCV2018上的最新工作:华科白翔老师团队ECCV2018 OCR论文:Ma ...
- 用百度文字识别实现图片文本识别
要用百度API则必须先注册百度开发者,然后才能使用百度的各项服务:地图API.文字语音转换API.文本识别API.....,文本识别的官方文档:文字识别-帮助与支持-百度云 注册完成后,需要用到以下三 ...
最新文章
- 浅谈 MVP in Android
- python条件语句-Python 条件语句
- VS2008 ,TFS2008破解序列号
- Qt把已有工程添加到其他工程中作为子工程或新创建子工程
- Docker - 安装并持久化PostgreSQL数据
- poj 1847 Tram 最短路 dijkstra、floyed
- kettle将文件路径定义为_Kettle变量和自己定义java代码的实例应用
- 如何设置程序默认“以管理员身份运行”
- 超分辨率谷歌卫星图下载经验贴
- 经方的魅力第二版》读书摘录
- coreutils8.32 hostid命令和源码分析
- imx6 Android gpu 内存,Use vivante GPU on IMX6 with 4.14 kernel
- ios 代码例子 卷边的翻书效果
- 【CuteJavaScript】GraphQL真香入门教程
- 使用Typora列表嵌套列表,回车无法返回上一级列表的状态
- 10年,从一个月薪2500的设备维修工,迫于压力转行,直到成为自动化测试专家···
- RK3288 EDP 调试
- PHP 多行文字内容的重复检测功能并统计重复次数
- syslog与syslog服务器的配置
- (已更新)最新打卡抽奖助手小程序源码,带微信通知功能,去授权
热门文章
- 安卓屏幕朗读app_你们要的小说App来了,永久免费不要钱,书源全网最全
- 美团点评开源 SQL 优化工具 SQLAdvisor 测试报告
- Matlab中十字线出不来,如何在MATLAB中实现已弃用的完整十字线指针功能?
- 20180125 high cohesive low coupling
- python词云是什么意思_python-词云
- 精密压接之曲柄连杆模型计算(含MATLAB仿真+博途SCL源代码)
- 【备忘】【No2】2016年最新云计算视频教程hadoop大数据实战开发
- 企业的Windows活动目录规划方案集合(附学习视频)
- 3DMax教程 教你在3DMax中怎么渲染黑色的描边 渲染黑色的描边有三种方法:
- java 写文件 0x0d_Java的文件读写操作 转