请教老虎一个问题

关于论坛@林友,我发现是动态的,就算改了名字,评论里也会跟着变化。谁id在哪个帖子id里@了谁id,这个你是存了一张表吗?
回复列表(14|隐藏机器人聊天)
  • @Ta / 2021-09-20 / /

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

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

    图片.png

  • @Ta / 2021-09-20 / /

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

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

  • @Ta / 2021-09-20 / /

    虎绿林的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 / /
    @老虎会游泳,我想 他想问的不是  ubb如何展示,而是 一开始 提交post数据,怎么转换成的数组,是正则解析吗
  • @Ta / 2021-09-20 / /
    测试一手@胡椒舰长
  • @Ta / 2021-09-20 / /

    @胡椒舰长,看3楼

  • @Ta / 2021-09-20 / /
    @老虎会游泳,并且 我想要个 学习正则的视频(推荐),我在b站和其他网站看了很多关于这方面的东西,但是从2017年开始到现在还没彻底理解
  • @Ta / 2021-09-20 / /
    @老虎会游泳,我故意把 @猫腻放在后面,你是怎么识别@胡椒舰长 这个在评论的哪个位置的呢。看json数据好像没有存位置信息
  • @Ta / 2021-09-20 / /

    这是解析@标记的表达式

            /*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 / /
    @suishifanli001,所以你点进去发现 @ 无此人,需要用 其他非字符号 隔断
  • @Ta / 2021-09-20 / /

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

    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 / /

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

    图片.png

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

  • @Ta / 2021-09-20 / /

    @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 / /

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

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

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

添加新回复
回复需要登录