• 编程疑难杂症の真的非常一样的文本?!


    image

    问题描述:

    首先,说明我要实现的功能:读取飞信聊天记录信息(TXT格式),并把凡是我发送的信息的发送人都放在“发送人2”这一列。即只要把信息中的发送人与界面上的“昵称”里面的字符串比对一样,即可!

    问题就在,当两条信息发送人(看起来)都是一样的时候,偏偏一条放在了“发送人1”,另外一条才放到“发送人2”!这是Bug样本截图

    [By:AsionTang]

    这是Bug样本文件:真的非常一样的文本.zip

    这是读取此信息的函数代码:

            private bool YEReadFeiXin(string Contents)
            {
                //只有飞信的导出才有【\t】,没有的话直接退出。
                if ( !Contents.Contains("\t(") )
                    return false;
                try
                {
                    #region 局部变量声明区
    
                    List<string> feixin = new List<string>();
                    List<string> feixinTEMP = new List<string>();
                    
                    string Separators1 =  "\t(";
                    string Separators2 =  "\r\n";
                    if ( Contents.Contains("\r\r\n") )
                        Contents = Contents.Replace("\r\r\n" , "\r\n");//把飞信2010版本的导出格式转换为之前的格式。o(︶︿︶)o 唉!
                    string Separators3 =  ")说:";
    
                    //定位当前【\t(】制表符的位置
                    int idxTab1 = 0;
    
                    //定位下一个Tab索引。
                    int idxTab2 = 0;
    
                    //定位当前制表符前面的该符号。
                    int idxNextLine1 = 0;
    
                    //定位从下个制表符开始的上一个【\r\n】符号所在位置
                    int idxNextLine2 = 0;
    
                    //定位【)说:  】的所在位置
                    int idx3 = 0;
    
                    //聊天的昵称
                    string name = "";
                    //发送时间
                    string time = "";
                    //聊天内容
                    string message = "";
    
                    bool isEnd = false;
    
                    #endregion
    
                    while ( !isEnd )
                    {
    
                        #region 分离各部分信息
                        /* 
                         * 枫之梦23\t(2010-10-19 23:31:00)说:  好了,你快些完成你今天的任务睡觉吧!\r\n我先睡咯!\r\n
                         * 枫之梦23\t(2010-10-19 23:31:00)说:  好了,你快些完成你今天的任务睡觉吧!\r\n我先睡咯!\r\n
                         * 枫之梦23\t(2010-10-19 23:31:00)说:  好了,你快些完成你今天的任务睡觉吧!\r\n我先睡咯!
                         */
                        //定位第一个[\t(]符号的位置。
                        idxTab1 = Contents.IndexOf(Separators1 , idxTab1 + 1);
    
                        //定位idxTab1前面的【\r\n】符号的位置。
                        idxNextLine1 = Contents.LastIndexOf(Separators2 , idxTab1);
                        if ( idxNextLine1 == -1 )
                            name = Contents.Substring(0, idxTab1);
                        else
                            name = Contents.Substring(idxNextLine1 + Separators2.Length , idxTab1 - idxNextLine1 - Separators2.Length);
    
                        //定位下一个【\t(】符号的位置。
                        idxTab2 = Contents.IndexOf(Separators1 , idxTab1 + 1);
    
                        //当不存在下一个【\t(】符号的时候,即没有下一行信息了。
                        if ( idxTab2 == -1 )
                        {
                            isEnd = true;
                            idxNextLine2 = Contents.Length;//除去后面占两个位的/r/n。
                        }
                        else
                        {
                            //定位从下个制表符开始的上一个【\r\n】符号所在位置
                            idxNextLine2 = Contents.LastIndexOf(Separators2 , idxTab2);
                        }
    
                        //定位【)说:  】的所在位置
                        idx3 = Contents.IndexOf(Separators3 , idxTab1);
    
                        time = Contents.Substring(idxTab1 + 2 , idx3 - idxTab1 - 2);
    
                        message = Contents.Substring(idx3 + 5 , idxNextLine2 - idx3 - 5);
    
                        #endregion
    
                        //输出显示。
                        int lastIndex = lsvMessageShower.Items.Count;
                        lsvMessageShower.Items.Add("飞信");
                        if ( name == MyNickName.Text )
                        {
                            lsvMessageShower.Items[ lastIndex ].SubItems.Add("");
                            lsvMessageShower.Items[ lastIndex ].SubItems.Add(name);
                        }
                        else
                        {
                            lsvMessageShower.Items[ lastIndex ].SubItems.Add(name);
                            lsvMessageShower.Items[ lastIndex ].SubItems.Add("");
                        }
                            
                        lsvMessageShower.Items[ lastIndex ].SubItems.Add(time);
                        lsvMessageShower.Items[ lastIndex ].SubItems.Add(message);
    
                    }
                    return true;
                }
                catch ( Exception ex )
                {
                    Debug.Print(ex.ToString());
                    return false;
                }
    
            }

    尝试解决

    上次发表有一篇同样类型的文章,《编程疑难杂症の无法剔除的神秘重复记录》,里面的问题原因就是所比对的字符串里面包含“不可见字符”。所以首先想到的就是这次是否是一样的问题,结果却很不幸的没有能够解决!以下是VS2008调试界面截图:

    image 可见,这里并没有什么特殊的“不可见字符”的。按照代码里面的逻辑,完全是可以把这两天信息完整的分离开来的。调试过程也证明了,代码逻辑并没有错。

    image

    我使用“监视”窗口,对提取出来的发送人Name变量,和界面上显示昵称的TextBox对象进行监视。看到的都是一样的字符串!

    至此,我真的不知道这个问题的原因了!期望哪位朋友能帮解决。

    程序源代码下载:

    源代码の聊天记录管理器110103.zip

    2011年1月3日 00:17:19
    By:AsionTang

    问题解决

    在此非常感谢xuld朋友,一句代码就帮解决了这个问题 。也就是使用name.Trim()函数,将前后的空白字符给去掉之后,问题得到了完美解决!

    问题解决之后,开始反思这个问题的产生原因。既然去掉的是空白字符,那么在记事本里面应该也能“感受”出来,于是打开Bug样本,使用左右方向键移动输入光标,果然,在第二行信息的开头,本应该只需移动一次就可以到下一个文字的,但是却移动了两次光标!

    image

    事后总结:

    由于这个问题首次碰到,所以之前一直都以为“空白字符”就是“空格”,而空格一般都是可见的。不过在此件事情之后,终于意识到,看不到的,未必就是没有的。至于以后还会不会出现同类型的Bug呢,就得学会该怎么查看这些“默认不可见”的字符了。

    在之前那篇文章中有位朋友评论说,曾经碰到一个情况是,字符编码不同,而导致的比对失败,而他又是靠着“十六位进制查看器”来发现其中的不同的!这也为以后出现类似问题的时候提供了一个解决途径,当VS调试器都无法查看到的时候,那么借助这个不同进制的查看器,应该就能看到隐藏的秘密了!

    作者:Asion Tang
    凡是没有注明[转载]的文章,本Blog发表的文章版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    golang以服务方式运行
    nginx重写规则配置
    PHP的 parse_ini_file 解析配置文件
    在Yii2中集成Markdown编辑器
    理解 is_callable
    Composer安装yii2-imagine 压缩,剪切,旋转,水印
    Yii2 基于header 实现接口版本控制
    (1) laravel php artisan list make
    php 阿里云国内短信实例
    php 云片国外短信实例
  • 原文地址:https://www.cnblogs.com/AsionTang/p/1924348.html
Copyright © 2020-2023  润新知