zoukankan      html  css  js  c++  java
  • 『实用』过滤字符串中的幽灵字符

    背景:

    一段明显的字符串,可能潜伏着看不见 的 幽灵字符。

    某些字符 比较常见、常用,比如:       

    但是,有些 幽灵字符(保守估计 >200~1000个),不仅不常见,而且基本没价值。

    这些幽灵字符,潜伏在 正常字符串中,有的伪装成空格符,有的直接隐形。

    当你要 处理字符串时,这些幽灵字符 的 恶意可能就开始显现 : 部分字符串函数 会因此引发BUG。

    PS. 本文看似简单,实际上好像确实很简单 —— 百毒相关知识点,可用信息 并不多。

           幽灵字符 不常见,即便檫肩而过 往往都没啥影响 —— 可一旦幽灵字符作恶起来,似乎都只能用 “诡异” 来形容。

    举例 1:

    如下代码,你看得出BUG么?

    //将一个字符串中的 连续空格 替换成 单空格 
    //【 隐形的幽灵字符 如果介于两个空格之间,本函数就会发生 死循环。】
    //【 即:string.IndexOf() 函数忽略了 隐形幽灵字符, 但 string.Replace() 函数却要求严格。】
    public static void FormatString(string sValue) { while (sValue.IndexOf(" ") >= 0) sValue = sValue.Replace(" ", " "); return sValue; }

    2012年的一个 BUG,几万个网页HTML 格式化,意外引发BUG,我才第一次见识到 幽灵字符 的厉害。

    举例 2:

    复制如下SQL脚本,到 SQLServer 中执行一下 —— 幽灵字符 显形了。

    1    SELECT '4  k×4  k' 

    如何剔除掉幽灵字符:

    正则表达式: s   (匹配字符串中的 空白字符,包括 空格 ... 也包括 幽灵字符)

    用正则替换幽灵字符:

     1         private static readonly  Regex m_RegSpace = new Regex(@"s", RegexOptions.Compiled | RegexOptions.IgnoreCase);
     2         /// <summary>
     3         /// 用正则表达式替换出 不常见、不常用 的幽灵字符
     4         /// </summary>
     5         public static string FormatStringByRegex(string str)
     6         {
     7             return m_RegSpace.Replace(str, m =>
     8             {
     9                 if (m.Value == " " || m.Value == "
    " || m.Value == "
    " || m.Value == "	") return m.Value;
    10                 return " ";
    11             });
    12         }

    性能问题:

    正则 s 确实是 万能的。

    但在 某些情况下,正则效率 很低 —— 即便我 启用了 编译模式  RegexOptions.Compiled

    于是,就有了下面的 最终代码,纯原生代码:支持 .Net 2.0 ~ .Net 4.6

    经过测试,使用 下面的 替换函数 比 使用正则 替换 效率快 10倍整。 

    而且:

    正则 s 无法有效区分:哪些 幽灵字符 是 隐形的,哪些 幽灵字符 是伪装成空格的。

    而我们想要的:隐形的幽灵字符 直接剔除,伪装成空格的幽灵字符 用 真正的空格代替。

    最终代码:

     1         /// <summary>
     2         /// 格式化一段字符串, 将字符串中的 非预期的 幽灵字符 删除.
     3         /// <para>本函数将保留 空白符 
     回车(CR) 
     换行(LF) 	 水平制表(HT) 这几个常用字符</para>
     4         /// <para>其他未知的 幽灵字符 将直接剔除. 极少使用的 幽灵字符 也会被剔除</para>
     5         /// </summary>
     6         public static string FormatString(string str)
     7         {
     8             return FormatString(str, false);
     9         }
    10         /// <summary>
    11         /// 格式化一段字符串, 将字符串中的 非预期的 幽灵字符 删除.
    12         /// <para>本函数将保留 空白符 
     回车(CR) 
     换行(LF) 	 水平制表(HT) 这几个常用字符</para>
    13         /// <para>preserveRare 参数决定如下字符是否保留(true: 保留, false 剔除, 默认 false剔除): a 响铃(BEL)  退格(BS) f 换页(FF) v 垂直制表(VT)  空字符(一般C++标识字符串结束) </para>
    14         /// <para>其他根本没见过的 幽灵字符 将直接剔除.</para>
    15         /// </summary>
    16         public static string FormatString(string str, bool preserveRare)
    17         {
    18             if (string.IsNullOrEmpty(str)) return string.Empty;
    19 
    20             StringBuilder sb = new StringBuilder();
    21             foreach (char c in str)
    22             {
    23                 if (c == ' ' || c == '
    ' || c == '
    ' || c == '	') { sb.Append(c); continue; }
    24                 if (c == 'a' || c == '' || c == 'f' || c == 'v' || c == '') { if (preserveRare) { sb.Append(c); } continue; }  //这段代码感觉有性能问题,但细品之下却发现:毫无破绽
    25                 if (!char.IsWhiteSpace(c)) { sb.Append(c); continue; }
    26 
    27                 //剩下的 幽灵字符 特殊处理:
    28                 //经过测试: 0x0 - 0xFFFFFF 的 char 字符中, 幽灵字符 要么是 控制符, 要么是分割符.
    29                 //如果是 分隔符, 我们将其替换成空格
    30                 //如果是 控制符, 我们将其直接剔除, 
    31                 if (char.IsSeparator(c)) { sb.Append(' '); continue; }
    32                 //if (char.IsControl(c)) continue; //无意义代码,不需要执行:剩下的字符 通通过滤掉
    33             }
    34 
    35             return sb.ToString();
    36         }

                                                                                                                                                                                          InkFx

                                                                                                                                                                                  2017-11-17 23:46

  • 相关阅读:
    实例属性 类属性 实例域 类域
    研究数据集
    static 静态域 类域 静态方法 工厂方法 he use of the static keyword to create fields and methods that belong to the class, rather than to an instance of the class 非访问修饰符
    accessor mothod mutator mothod 更改器方法 访问器方法 类的方法可以访问类的任何一个对象的私有域!
    上钻 下钻 切片 转轴 降采样
    识别会话
    Performance Tuning Using Linux Process Management Commands
    Secure Hash Algorithm 3
    grouped differently across partitions
    spark 划分stage Wide vs Narrow Dependencies 窄依赖 宽依赖 解析 作业 job stage 阶段 RDD有向无环图拆分 任务 Task 网络传输和计算开销 任务集 taskset
  • 原文地址:https://www.cnblogs.com/shuxiaolong/p/Ghost_Char.html
Copyright © 2011-2022 走看看