php从小说章节标题中获取章节索引

臭大佬 2022-04-02 16:51:52 1781
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);
    }