『实⽤』过滤字符串中的幽灵字符
背景:
⼀段明显的字符串,可能潜伏着看不见的幽灵字符。
某些字符⽐较常见、常⽤,⽐如: \r  \n  \t
但是,有些幽灵字符(保守估计 >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 中执⾏⼀下 —— 幽灵字符显形了。
1SELECT'4  k×4  k'
如何剔除掉幽灵字符:
正则表达式: \s  (匹配字符串中的空⽩字符,包括空格 \r \n \t ... 也包括幽灵字符)
⽤正则替换幽灵字符:
1private static readonly  Regex m_RegSpace = new Regex(@"\s", RegexOptions.Compiled | RegexOptions.IgnoreCase);
2///<summary>
3///⽤正则表达式替换出不常见、不常⽤的幽灵字符
4///</summary>
5public static string FormatStringByRegex(string str)
6        {
7return m_RegSpace.Replace(str, m =>
8            {
9if (m.Value == "" || m.Value == "\r" || m.Value == "\n" || m.Value == "\t") return m.Value;
字符串复制函数10return"";
11            });
12        }
性能问题:
正则 \s 确实是万能的。
但在某些情况下,正则效率很低 —— 即便我启⽤了编译模式  RegexOptions.Compiled
于是,就有了下⾯的最终代码,纯原⽣代码:⽀持 .Net 2.0 ~ .Net 4.6
经过测试,使⽤下⾯的替换函数⽐使⽤正则替换效率快 10倍整。
⽽且:
正则 \s ⽆法有效区分:哪些幽灵字符是隐形的,哪些幽灵字符是伪装成空格的。
⽽我们想要的:隐形的幽灵字符直接剔除,伪装成空格的幽灵字符⽤真正的空格代替。
最终代码:
1///<summary>
2///格式化⼀段字符串, 将字符串中的⾮预期的幽灵字符删除.
3///<para>本函数将保留空⽩符 \r 回车(CR) \n 换⾏(LF) \t ⽔平制表(HT) 这⼏个常⽤字符</para>
4///<para>其他未知的幽灵字符将直接剔除. 极少使⽤的幽灵字符也会被剔除</para>
5///</summary>
6public static string FormatString(string str)
7        {
8return FormatString(str, false);
9        }
10///<summary>
11///格式化⼀段字符串, 将字符串中的⾮预期的幽灵字符删除.
12///<para>本函数将保留空⽩符 \r 回车(CR) \n 换⾏(LF) \t ⽔平制表(HT) 这⼏个常⽤字符</para>
13///<para>preserveRare 参数决定如下字符是否保留(true: 保留, false 剔除, 默认 false剔除): \a 响铃(BEL) \b 退格(BS) \f 换页(FF) \v 垂直制表(VT) \0 空字符(⼀般C++标识字符串结束) </para> 14///<para>其他根本没见过的幽灵字符将直接剔除.</para>
15///</summary>
16public static string FormatString(string str, bool preserveRare)
17        {
18if (string.IsNullOrEmpty(str)) return string.Empty;
19
20            StringBuilder sb = new StringBuilder();
21foreach (char c in str)
22            {
23if (c == '' || c == '\r' || c == '\n' || c == '\t') { sb.Append(c); continue; }
24if (c == '\a' || c == '\b' || c == '\f' || c == '\v' || c == '\0') { if (preserveRare) { sb.Append(c); } continue; }  //这段代码感觉有性能问题,但细品之下却发现:毫⽆破绽25if (!char.IsWhiteSpace(c)) { sb.Append(c); continue; }
26
27//剩下的幽灵字符特殊处理:
28//经过测试: 0x0 - 0xFFFFFF 的 char 字符中, 幽灵字符要么是控制符, 要么是分割符.
29//如果是分隔符, 我们将其替换成空格
30//如果是控制符, 我们将其直接剔除,
31if (char.IsSeparator(c)) { sb.Append(''); continue; }
32//if (char.IsControl(c)) continue; //⽆意义代码,不需要执⾏:剩下的字符通通过滤掉
33            }
34
35return sb.ToString();
36        }
InkFx
2017-11-17 23:46

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。