php从小说章节标题中获取章节索引
简介
运用场景:从小说章节标题中提取章节索引
前言
最近在对接一个小说系统,其中有一个需求是:
小说的前N
章是免费无广告的,之后的章节要添加一些广告进去的。
研究了一下小说的整个字段,并没有发现数字索引,
本着不懂就问的精神,找了对接的小说商,他的回答就是标题上有第几章,别的地方是没有体现的。
由于后期可能需要多种渠道获取小说资源,所以,我想看看市面上别的小说是不是也是这么一种形式。
于是我又找了一些免费小说网站,还研究了几个开源的小说采集工具。无论是免费小说网站,还是采集工具,小说的章节数字索引都是没有的,一般都是用一段唯一的key作为小说的索引,而章节之间的连接,有点像链表,在每一章中,都有前一章的key,以及后一章的key。
和对接的厂商说的差不多,就发现只有title
字段能知道这篇文章的数字索引。但是,title
字段又存在好几种形式,目前对接的发现有以下几种:
第164章纪元战场
第一百四十二章 阴兵过境、城隍引路
001 国破家亡
8.吾辈仙族当舍身侍龙
那就是需要在title
中提取小说数字索引了。
分析上面的标题,可以发现,要解决的是以下几个问题。
问题
根据已知的标题形式,我们梳理一下规则和逻辑。
第一种标题第164章纪元战场
:这种情况只要提取第
和章
中间的数字就行;
第二种标题第一百四十二章 阴兵过境、城隍引路
:第二种需要先把汉字转化成数字,再用第一种的方法提取;
第三种标题001 国破家亡
:需要去除数字前面的0
,然后空格截取;
第四种标题8.吾辈仙族当舍身侍龙
:根据英文.
截取;
实现
已经知道了匹配规则,那我们就可以用代码去实现了。方法如下:
- 方法
strToNum()
:汉字数字转化成阿拉伯数字; - 方法
delNumberBeforeZero()
:去除数字前面的0
; - 方法
getFromStr()
:截取指定两个字符之间字符串。
/**
* Description:去除数字前面的0
* User: Vijay <1937832819@qq.com>
* Site: https://www.choudalao.com/
* Date: 2022/4/2
* Time: 15:42
* @param $str
* @return string|string[]|null
*/
function delNumberBeforeZero($str)
{
return preg_replace('/^0+/', '', $str);
}
/**
* Description:汉字数字转化成阿拉伯数字
* User: Vijay <1937832819@qq.com>
* Site: https://www.choudalao.com/
* Date: 2022/4/2
* Time: 15:43
* @param $str
* @return string|string[]
*/
function strToNum($str)
{
$arr1 = ['零' => '', '一' => 1, '二' => 2, '三' => 3, '四' => 4, '五' => 5, '六' => 6, '七' => 7, '八' => 8, '九' => 9];
$arr2 = ['亿' => 100000000, '千万' => 10000000, '百万' => 1000000, '十万' => 100000, '万' => 10000, '千' => 1000, '百' => 100, '十' => 10];
preg_match_all('/(零|一|二|三|四|五|六|七|八|九|十|百|千|万|亿)+/i', $str, $result);
if (empty($result[0][0])) return $str;
else $tmp = $result[0][0];
$tmp = str_replace(array_keys($arr1), array_values($arr1), $tmp);
foreach ($arr2 as $k => $v) {
if (strlen($tmp) == 1) $tmpArr[1] = $tmp;
else if (strpos($tmp, $k) !== false) {
$tmpArr[$v] = getFromStr('', $k, $tmp);
$tmp = getFromStr($k, '', $tmp);
if (strlen($tmp) == 1) $tmpArr[1] = $tmp;
}
}
if (is_array($tmpArr)) {
$num = 0;
foreach ($tmpArr as $k => $v) {
if (empty($v)) $v = 1;
$num += $k * $v;
}
}
if (!empty($num)) return str_replace($result[0][0], $num, $str); else return $str;
}
/**
* Description:截取指定两个字符之间字符串
* User: Vijay <1937832819@qq.com>
* Site: https://www.choudalao.com/
* Date: 2022/4/2
* Time: 15:44
* @param $start
* @param $end
* @param $str
* @return false|string
*/
function getFromStr($start, $end, $str)
{
if (!empty($start)) $str = substr($str, strpos($str, $start) + strlen($start), strlen($str) - strlen($start) - strpos($str, $start));
if (!empty($end)) $str = substr($str, 0, strpos($str, $end));
return $str;
}
通用方法有了,获取索引的方法如下:
/**
* Description:根据标题形式提取章节序号
* User: Vijay <1937832819@qq.com>
* Site: https://www.choudalao.com/
* Date: 2022/4/2
* Time: 15:53
* @param $str
* @return false|int|mixed|string|string[]|null
*/
function getIndex($str)
{
$index = 0;
if (strpos($str, '第') !== false && strpos($str, '章') !== false) {
$index = getFromStr('第', '章', $str);
} elseif (strpos($str, '.') !== false) {
$str = explode('.', $str);
if (isset($str[0])) {
$index = $str[0];
}
} elseif (strpos($str, ' ') !== false) {
$str = explode(' ', $str);
if (isset($str[0])) {
$index = $str[0];
}
}
// 补充其他规则
// ...
$index = delNumberBeforeZero($index);
return $index;
}
测试:
public function testA()
{
//$title = '第一百四十二章 阴兵过境、城隍引路';
//$title = '第164章纪元战场';
//$title = '091 国破家亡';
$title = '08.吾辈仙族当舍身侍龙';
$index = strToNum($title);
$index = getIndex($index);
print_r($index);
}