热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

文本识别标题后分割_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($callbackSize); //回调函数,分段期间做的事$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文件,然后做记录

/*** 根据行数分割文件* &#64;param $fileName* &#64;param $start* &#64;param $limit* &#64;return string*/public static function getLine($fileName,$start,$limit){$f&#61; new \SplFileObject($fileName,&#39;r&#39;);$f->seek($start); //文件指针指向行数$ret&#61;&#39;&#39;;for ($i&#61;0;$i<$limit;$i&#43;&#43;){$ret.&#61;$f->current(); //内容$f->next(); //下一行}return $ret;}

  • 该方法是根据文本行数&#xff0c;将文本进行分割&#xff0c;返回分割文本内容

/*** 生成章节文件* &#64;param $chapterPath* &#64;param $content* &#64;return false|mixed*/public static function ChapterTxt($chapterPath,$content){if (help::fileIsHas($chapterPath))return false;$fp&#61;fopen($chapterPath,&#39;wb&#39;)or die(__("can&#39;t open this file :".$chapterPath));fwrite($fp,$content);fclose($fp);return $chapterPath;}

  • 该方法是根据文本内容生成txt文件导出&#xff0c;返回路径
  • txt文件导出&#xff0c;其实就是写入文件&#xff0c;若文件不存在则会新建
  • fopen中 wb 的b &#xff0c;意思是window&#xff0c;和linux写入一致格式&#xff0c;不然会window文本放到linux系统会有文本内容win格式问题

七、入库、做记录

整体调用总函数

/*** 上传整本小说&#xff0c;分割章节&#xff0c;然后更新库* &#64;param string $path* &#64;param array $novels_id* &#64;param string $patten* &#64;throws \think\exception\DbException*/public static function wholeNovelsChapters(string $path,int $novels_id,string $patten&#61;"/chapter[\s][A-Z]&#43;\./i"){/*$dir&#61;novels_opeate::sectionalizer($path,function($size)use($path,$patten,$dir){$dir[]&#61;novels_opeate::pregChapters($path,$patten,$size); //分段将目录导入dir数组内return $dir;});*/$dir&#61;novels_opeate::pregChapters($path,$patten,filesize($path))[0]; //获取章节目录$chaptersNum&#61;novels_opeate::ChaptersLine($path,$dir); //获取章节目录所在的行数$word_count&#61;novels_opeate::splitByChapter($path,$chaptersNum,$novels_id); //分割整本书&#xff0c;生成章节txt文件,入库$chaptersNum&#61;array_sum($chaptersNum);novels_model::where(&#39;id&#39;,$novels_id) //更新小说表->update([&#39;path&#39;&#61;>dirname($path).DS,&#39;chapter_count&#39;&#61;>$chaptersNum, //小说章节总数&#39;word_count&#39;&#61;>$word_count,]);unlink($path); //删除原本}

  • 当初实现时候思维比较混乱&#xff0c;时间仓促没有使用分割器&#xff0c;后期可以优化
  • 其实用多线程的话&#xff0c;性能会大幅度提升&#xff0c;而且更加简便&#xff0c;后期有兴趣可以试试
  • 本文有个弊端&#xff0c;就是文本标题是正则选取&#xff0c;如果上传的文本章节标题和正则不相符&#xff0c;则会失去作用&#xff0c;所以需要提供具体章节标题
  • 本文使用的正则规则&#xff0c;“/chapter[\s][A-Z]&#43;./i”&#xff0c;可以识别CHAPTER II.

推荐阅读
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • PHPMailer邮件类邮件发送功能的使用教学及注意事项
    本文介绍了使用国外开源码PHPMailer邮件类实现邮件发送功能的简单教学,同时提供了一些注意事项。文章涵盖了字符集设置、发送HTML格式邮件、群发邮件以及避免类的重定义等方面的内容。此外,还提供了一些与PHP相关的资源和服务,如传奇手游游戏源码下载、vscode字体调整、数据恢复、Ubuntu实验环境搭建、北京爬虫市场、进阶PHP和SEO人员需注意的内容。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 1简介本文结合数字信号处理课程和Matlab程序设计课程的相关知识,给出了基于Matlab的音乐播放器的总体设计方案,介绍了播放器主要模块的功能,设计与实现方法.我们将该设 ... [详细]
  • javascript二叉树基本功能实现
    都是常用的功能。删除是最复杂的。。test ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文介绍了Java后台Jsonp处理方法及其应用场景。首先解释了Jsonp是一个非官方的协议,它允许在服务器端通过Script tags返回至客户端,并通过javascript callback的形式实现跨域访问。然后介绍了JSON系统开发方法,它是一种面向数据结构的分析和设计方法,以活动为中心,将一连串的活动顺序组合成一个完整的工作进程。接着给出了一个客户端示例代码,使用了jQuery的ajax方法请求一个Jsonp数据。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 【爬虫】关于企业信用信息公示系统加速乐最新反爬虫机制
    ( ̄▽ ̄)~又得半夜修仙了,作为一个爬虫小白,花了3天时间写好的程序,才跑了一个月目标网站就更新了,是有点悲催,还是要只有一天的时间重构。升级后网站的层次结构并没有太多变化,表面上 ... [详细]
author-avatar
我从不在乎O心痛
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有