已掉线,重新登录

首页 > 绿虎论坛 > 杂类 > 超级灌水 (发帖)

标题: 请教老虎一个问题

作者: @Ta

时间: 2021-09-20

点击: 3148

关于论坛@林友,我发现是动态的,就算改了名字,评论里也会跟着变化。谁id在哪个帖子id里@了谁id,这个你是存了一张表吗?

[隐藏样式|查看源码]


『回复列表(14|隐藏机器人聊天)』

1.

@suishifanli001,访问这个链接你就能发现,虎绿林的帖子内容不是纯文本的,而是JSON数组。虎绿林通过UBB解析,将帖子内容转换成PHP数组存储在数据库,对于@标记会存储uid,在显示时遍历数组动态生成内容,此时就能查询uid最新的用户名了。

https://hu60.cn/q.php/bbs.topic.101538.json?_content=json

图片.png

(/@Ta/2021-09-20 21:23//)

2.

这个链接可以更好的展示虎绿林怎么存储帖子数据,它几乎展示了每种UBB类型的数组结构:

https://hu60.cn/q.php/bbs.topic.80645.json?_content=json

(/@Ta/2021-09-20 21:26//)

3.

虎绿林的UBB解析器是一个使用正则表达式实现的递归下降解析器:

https://github.com/hu60t/hu60wap6/blob/master/src/class/xubbp.php
https://github.com/hu60t/hu60wap6/blob/master/src/class/ubbparser.php

解析过程:

  1. 遍历正则表达式,逐个与内容进行匹配,直到遇到第一个匹配的表达式。
  2. 表达式把内容分成3个部分:前文、UBB标记、后文。
  3. 对UBB标记调用相应的处理函数,将其转换为数组。
  4. 对前文和后文递归调用过程1,于是所有UBB标记都逐个被转换为数组。
  5. 如果所有表达式都与内容不匹配,就将内容转换为type=>"text"(正文)的数组,结束递归。
        /*code 代码高亮*/
        '!^(^|.*?[\r\n]+)\[code(?:=(\w+))?\]([\r\n]+.*?[\r\n]+)\[/code\]([\r\n]+.*|$)$!is' => array(array(1, 4), 'code', array(2, 3)),
        '!^(.*?)\[code(?:=(\w+))?\](.*?)\[/code\](.*)$!is' => array(array(1, 4), 'code', array(2, 3)),
        /*time 时间*/
        '!^(.*?)\[time(?:=(.*?))?\](.*)$!is' => array(array(1, 3), 'time', array(2)),
        /*link 链接*/
        '!^(.*?)\[url(?:=(.*?))?\](.*?)\[/url\](.*)$!is' => array(array(1, 4), 'link', array('url', 2, 3)),
        '!^(.*?)《(链接|外链|锚):(.*?)》(.*)$!is' => array(array(1, 4), 'link', array(2, 3)),
        /*img 图片*/
        '!^(.*?)\[img(?:=(.*?))?\](.*?)\[/img\](.*)$!is' => array(array(1, 4), 'img', array('img', 2, 3)),
        '!^(.*?)《(图片|缩略图):(.*?)》(.*)$!is' => array(array(1, 4), 'img', array(2, 3)),
        '!^(.*?)《表情(?::|:)(.*?)》(.*)$!uis' => array(array(1, 3), 'face', array(2)),
        /*video 视频*/
        '!^(.*?)《视频:(.*?)》(.*)$!is' => array(array(1, 3), 'video', array(2)),
        /*videoStream 视频*/
        '!^(.*?)《视频流:(.*?)》(.*)$!is' => array(array(1, 3), 'videoStream', array(2)),
        /*audio 音频*/
        '!^(.*?)《音频:(.*?)》(.*)$!is' => array(array(1, 3), 'audio', array(2)),
        /*audioStream 视频*/
        '!^(.*?)《音频流:(.*?)》(.*)$!is' => array(array(1, 3), 'audioStream', array(2)),
(/@Ta/2021-09-20 21:41//)

4. @老虎会游泳,我想 他想问的不是  ubb如何展示,而是 一开始 提交post数据,怎么转换成的数组,是正则解析吗
(/@Ta/2021-09-20 21:33//)

5. 测试一手@胡椒舰长
(/@Ta/2021-09-20 21:34//)

6.

@胡椒舰长,看3楼

(/@Ta/2021-09-20 21:34//)

7. @老虎会游泳,并且 我想要个 学习正则的视频(推荐),我在b站和其他网站看了很多关于这方面的东西,但是从2017年开始到现在还没彻底理解
(/@Ta/2021-09-20 21:35//)

8. @老虎会游泳,我故意把 @猫腻放在后面,你是怎么识别@胡椒舰长 这个在评论的哪个位置的呢。看json数据好像没有存位置信息
(/@Ta/2021-09-20 21:36//)

9.

这是解析@标记的表达式

        /*at @消息*/
        '!^(.*?)[@@]([@@##a-zA-Z0-9\x{4e00}-\x{9fa5}_-]+)(.*)$!uis' => array(array(1, 3), 'at', array(2)),

及其对应的处理函数:

    /**
     * @brief at消息
     */
    function at($tag)
    {
        $tag = str_replace('@', '@', $tag);
        $arr = explode('@', $tag);
        if (count($arr) > 1) {
            $result = array();
            foreach ($arr as $v) {
                $res = $this->at($v);
                $result = array_merge($result, $res);
            }
            return $result;
        }
        global $USER;
        //user的at方法产生at消息并返回at对象的uid
        //会生成at信息的页面须用regAt()方法注册at消息
        //若未注册,则不产生at消息,但uid正常返回
        if (!is_object($USER)) {
            $user = new user;
        } else {
            $user = $USER;
        }
        $uid = $user->at($tag);
        return array(array(
            'type' => 'at',
            'tag' => trim($tag),
            'uid' => $uid,
        ));
    }

可以看到,最后转化为了这样的数组:

        array(array(
            'type' => 'at',
            'tag' => trim($tag),
            'uid' => $uid,
        ));
(/@Ta/2021-09-20 21:39//)

10. @suishifanli001,所以你点进去发现 @ 无此人,需要用 其他非字符号 隔断
(/@Ta/2021-09-20 21:40//)

11.

一旦内容变成了数组,显示的时候就能想怎么操作就怎么操作了:

https://github.com/hu60t/hu60wap6/blob/master/src/class/ubbdisplay.php

    /*at用户名*/
    public function at($data)
    {
        global $PAGE;

        $jsFunc = $this->getOpt('at.jsFunc');
        $uid = (int)$data['uid'];
        $uinfo = new UserInfo();
        $uinfo->uid($uid);
        $name = $uinfo->name === null ? $data['tag'] : $uinfo->name;

        if ($jsFunc) {
            return '<a class="userat" href="#" onclick="' . $jsFunc . '(\'' . $name . '\',this);return false">@</a><a class="userinfo" href="user.info.' . $uid . '.' . $PAGE->bid . '">' . code::html($name) . '</a>';
        } else {
            return '<a class="userinfo" href="user.info.' . $uid . '.' . $PAGE->bid . '">@' . code::html($name) . '</a>';
        }
    }
(/@Ta/2021-09-20 21:43//)

12.

@suishifanli001,每个UBB标签(包括正文,正文是text标签)都是一个JSON对象,这些对象罗列成一个JSON数组,数组是有序的,数组的顺序就是标签出现在帖子里的顺序:

图片.png

所以只要从头遍历这个JSON数组,把里面的每个JSON对象都转换成HTML然后相连,就能得到帖子的显示结果。
如果遍历数组时把每个JSON对象都转换成UBB文本然后相连,就能得到帖子的原始输入。

(/@Ta/2021-09-20 21:49//)

13.

@suishifanli001,那么在解析时是怎么存储顺序的呢?

正则表达式将内容分成3部分,前文、UBB标记、后文。
UBB标记被当场转换为数组。
前文和后文通过递归调用随后被转换为数组。
然后将这些数组按[前文数组, UBB标记数组, 后文数组]的顺序合并。
这样最终得到的结果就是有序的,标签对象的顺序就是帖子内容的顺序。

https://github.com/hu60t/hu60wap6/blob/master/src/class/xubbp.php#L226

    /**
     * 递归解析文本
     */
    protected function parser($text)
    {
        if ($text == '') return array();
        foreach ($this->parse as $k => $v) {
            $arr = array();
            $this->tmp_parse_result = &$arr;
            $this->tmp_parse_param = $v;
            $ok = preg_replace_callback($k, array($this, 'parseExec'), $text);
            if ($ok === NULL) throw new xubbpException("正则表达式 '$k' 错误,匹配失败或达到PHP上限!\n内容过长可能会引发该问题。如果缩减内容后依然无法发送,请联系站长解决。"/*."\n引起错误的文本:$text"*/, 500);
            if ($arr === NULL) throw new xubbpException("正则表达式  '$k' 的回调函数 '$v[1]' 返回值错误,应该返回二维数组!\n请联系站长修复该问题", 501);
            if ($ok == '') return $arr;
        }
        return $this->parseText($text);
    }

    /**
     * 使用回调函数执行递归解析
     */
    protected function parseExec($argv)
    {
        $arr = &$this->tmp_parse_result;
        $v = $this->tmp_parse_param;
        $func = $v[1];
        $param = $v[2];
        foreach ($param as &$tmpV) {
            if (is_int($tmpV)) $tmpV = $argv[$tmpV];
        }
        $arr = array_merge($this->parser($argv[$v[0][0]]), call_user_func_array(array($this, $func), $param), $this->parser($argv[$v[0][1]]));
        return '';
    }
(/@Ta/2021-09-20 21:55//)

14.

@胡椒舰长,最好的教程在这里:

把目录中的每一个内容都看一遍,就会对Perl兼容正则表达式(PCRE)有完整充分的认识。

备注:从User Contributed Notes开始是用户留言,看到它就说明这篇内容结束了,可以回到目录看下一篇了。

(/@Ta/2021-09-20 22:11//)

回复需要登录

7月2日 04:11 星期三

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1