zoukankan      html  css  js  c++  java
  • 无服务器端的UDP群聊功能剖析(新增QQ表情功能)

    上一篇中,我们讲解的是这个小软件的重构:使用可二进制化的Model类代替拼接字符串的方式,这样做的好处是使得代码可读性更强,更容易维护,当然,也更符合面向对象的思想:处处皆对象。

    效果图览

    在这一篇中,主要涉及的内容是新增的QQ表情功能。这个功能的设计牵涉到了正则表达式,我们先来看看截图:

    弹出选择表情面板:

    3个用户的具体聊天内容:

    看到GIF图像在跳动

    其中有一个用户已经下线

    下面是设计的准备工作:

    首先,我们需要一个能够支持图片输入的TextBox,这里我选择了这篇文章中介绍的控件:C# 实现IM聊天信息输入显示控件(1)-显示GIF动画图片,这个控件通过QQ自带的ImageOle.dll ActiveX控件实现插入动画表情,所以说在使用之前,需要先利用regsvr32.exe命令注册这个dll,具体命令为:regsvr32.exe ImageOle.dll。

    当然做完了之后,直接在VS中添加COM引用即可。

    其次,弹出选择表情面板是必不可少的,这里我们利用一个二维的PictureBox数组来存储GIF表情动画,并放置到Panel容器中:

    View Code
    private void LoadingEmotion()
            {
                PictureBox[,] picList = new PictureBox[5,10];
                for (int i = 0; i < 5; i++)
                {
                    for (int j = 0; j < 10; j++)
                    {
                        int emotionSequenceCount = i * 10 + j;
                        picList[i,j] = new PictureBox();
                        picList[i, j].Height = picList[i, j].Width = 24;
                        picList[i, j].Image = Image.FromFile(".\\Face2\\" + emotionSequenceCount + ".gif");
                        picList[i, j].Top = i * 24;
                        picList[i, j].Left = j * 24;
                        picList[i, j].Tag = "#(" + emotionSequenceCount + ")#";
                        picList[i, j].Parent = panImg;
                        picList[i, j].Click += new EventHandler((sender, e) => 
                        { 
                            this.rSendContent.AppendText("#(" + emotionSequenceCount + ")#");
                            emotionFlag = false;
                            this.panImg.Visible = emotionFlag;
                        });
                        panImg.Controls.Add(picList[i,j]);
                    }
                }
            }

    上面的GIF动画位置是通过对象的Top和Left方法来控制的,非常的方便;同时,把每个GIF表情的代码放到了Tag中进行保存,以方便调用,并且利用了匿名方法来注册PictureBox的点击事件。每次点击图标,会自动在发送文本框中生成类似#(0)#或者#(1)#等的代码,这些代码代表了是哪个表情,比如#(0)#就代表了第一行一列的表情,#(1)#代表了第1行2列的表情,依次类推。

    最后就是输入的时候,如何进行表情匹配了。比如用户输入了如下的内容:

    Hello Shi#(0)#, How are you today?#(1)##(2)#

    其中#(0)#,#(1)#,#(2)#是由我们通过点击表情输入进去的,那么发送到对方的机器上的时候,就需要被解析成

    Hello Shi, How are you today?

    ,该如何进行呢? 

    其实,我的做法就是在这句话的头部和尾部加上#(S)#和#(E)#标记以区别头尾,

    #(S)#Hello Shi#(0)#, How are you today?#(1)##(2)##(E)#

    然后,通过如下的正则来进行分段匹配,其中,?=的作用主要是负向前查找,但是不包含本身。具体内容请参见正则表达式点滴2

    Regex regex = new Regex(@"(#\([0-9|S|E]+\)#).*?(?=#\([0-9|S|E]+\)#)", RegexOptions.Singleline | RegexOptions.IgnoreCase);

    那么得到的结果就被分成了几段:

    #(S)#Hello Shi

    #(0)#, How are you today?

    #(1)#

    #(2)#

    #(S)#

    这就是分成的5段,然后观察这5段就发现,每段开始都是一个图片的标记(#(S)#和#(E)#除外,那是开始结束标志),然后跟着的是一段文本或者是什么都不跟。

    那么这样的话,我们再继续对这些段进行区分:

    Regex regexImage = new Regex(@"(#\([0-9|S|E]+\)#)", RegexOptions.Singleline | RegexOptions.IgnoreCase);
    Regex regexPlainText = new Regex(@"(?<=(#\([0-9|S|E]+\)#)).*", RegexOptions.Singleline | RegexOptions.IgnoreCase);

    其中

    regexImage主要匹配其中的图片标记,比如#(0)#,

    regexPlainText主要匹配其中的文本或者空白字段,拿第二段来说,匹配的结果就是:

    #(0)#

    , How are you today?

    这样就将表情和文本完全分离出来了,最后直接将表情文字替换为真实图片,并添加到信息窗体中:

    if (!String.IsNullOrEmpty(matchImage.Value))
    {
        if (!matchImage.Value.Contains("#(S)#"))
        {
            rAllContent.InsertImageUseImageOle(".\\Face2\\" + matchImage.Value.Replace("#(", string.Empty).Replace(")#", string.Empty) + ".gif");
        }
        rAllContent.AppendText(matchPlainText.Value);
    }

    这里补充一下本新增功能中用到的正则知识:

    • 向前查找

    从语法上看,一个向前查找模式其实就是一个以?=开头的子表达式,需要匹配的文本跟在=的后面。

    比如我们需要知道一些URL用的是http还是https,则可以利用向前查找:

    http://www.cnblogs.com

    正则匹配为:.+(?=:)

    结果为: http

    如果利用.+(:) ,则为 http:

    • 向后查找

    也就是查找出现在被匹配文本之前的字符(但不消费它),操作符是?<=

    文本为:ABC0:  $12.56

    匹配为:  (?<=\$)[0-9.]+

    如果不佳?<=,结果为$12.56,反之为12.56

    • 向前向后查找集合

    例如以下文本:

    <head>

    <title>Ben Forta’s HomePage</title>

    </head>

    这里我们如果想得到<title>与</title>标签内的内容,但是不包含<title>和</title>标签,如果不利用向前向后查找的话,将显得异常麻烦。利用向前向后匹配,只需要一个正则表达式就可以搞定:

    正则匹配为:(?<=<title>).*?(?=</title>)

    刚刚说道的向前向后查找,说准确点应该叫做正向前查找和正向后查找。当然,这里还存在这负向前查找和负向后查找:

    操作符

    说明

    (?=)

    正向前查找

    (?!)

    负向前查找

    (?<=)

    正向后查找

    (?<!)

    负向后查找

    • 负向后查找

    文本为:I paid $30 for 100 apples.

    匹配为:\b(?<!\$)\d+\b

    这个的意思是查找不带有$符号的数字,这里的匹配结果是100

    当然,负向前查找和这个使用方式类似,暂略。

    全部代码如下:

    View Code
    public static void AddContent(string text,ChatRichTextBox rAllContent)
            {
                //解析发送的内容,实现表情匹配。
                    string sendText = "#(S)#" + text + "#(E)#";
                    Regex regex = new Regex(@"(#\([0-9|S|E]+\)#).*?(?=#\([0-9|S|E]+\)#)", RegexOptions.Singleline | RegexOptions.IgnoreCase);
                    Regex regexImage = new Regex(@"(#\([0-9|S|E]+\)#)", RegexOptions.Singleline | RegexOptions.IgnoreCase);
                    Regex regexPlainText = new Regex(@"(?<=(#\([0-9|S|E]+\)#)).*", RegexOptions.Singleline | RegexOptions.IgnoreCase);
                    MatchCollection matches = regex.Matches(sendText);
                    foreach (Match match in matches)
                    {
                        string matchedValue = match.Value;
    
                        Match matchImage = regexImage.Match(matchedValue);
                        Match matchPlainText = regexPlainText.Match(matchedValue);
    
                        if (!String.IsNullOrEmpty(matchImage.Value))
                        {
                            if (!matchImage.Value.Contains("#(S)#"))
                            {
                                rAllContent.InsertImageUseImageOle(".\\Face2\\" + matchImage.Value.Replace("#(", string.Empty).Replace(")#", string.Empty) + ".gif");
                            }
                            rAllContent.AppendText(matchPlainText.Value);
                        }
                    }
    
            }

    源码下载

    点击这里下载源码

  • 相关阅读:
    vs code 编译python 输出到调试控制台
    vs code个性化设置
    IDEA 简拼输入
    微信小程序 audio组件 默认控件 无法隐藏/一直显示/改了controls=‘false’也没用2019/5/28
    win10的cortana搜索显示空白
    微信小程序tabbar不显示2019.04.06
    读《提问的智慧》有感
    CLion 控制台输出内容乱码问题的解决方法
    vs code C语言环境搭建
    利用python的爬虫技术爬去糗事百科的段子
  • 原文地址:https://www.cnblogs.com/scy251147/p/2748840.html
Copyright © 2011-2022 走看看