如何快速替换数组中的字符

Sco*_*ain 4 c# optimization

我在XML文件上使用XML文本阅读器,该文件可能包含对读者无效的字符.我最初的想法是创建我自己的流阅读器版本并清除坏角色,但它严重减慢了我的程序.

public class ClensingStream : StreamReader
{
        private static char[] badChars = { '\x00', '\x09', '\x0A', '\x10' };
    //snip
        public override int Read(char[] buffer, int index, int count)
        {
            var tmp = base.Read(buffer, index, count);

            for (int i = 0; i < buffer.Length; ++i)
            {
                //check the element in the buffer to see if it is one of the bad characters.
                if(badChars.Contains(buffer[i]))
                    buffer[i] = ' ';
            }

            return tmp;
        }
}
Run Code Online (Sandbox Code Playgroud)

根据我的探查器,代码花了88%的时间用于if(badChars.Contains(buffer[i]))正确的方法,所以我没有造成可怕的缓慢?

Guf*_*ffa 8

它在该行中花费如此多时间的原因是因为该Contains方法循环遍历数组以查找该字符.

把字符放在一个HashSet<char>代替:

private static HashSet<char> badChars =
  new HashSet<char>(new char[] { '\x00', '\x09', '\x0A', '\x10' });
Run Code Online (Sandbox Code Playgroud)

检查集合是否包含字符的代码与查看数组时的代码相同,但它使用字符的哈希码来查找它,而不是循环遍历数组中的所有项目.

或者,您可以将字符放在开关中,这样编译器就可以创建有效的比较:

switch (buffer[i]]) {
  case '\x00':
  case '\x09':
  case '\x0A':
  case '\x10': buffer[i] = ' '; break;
}
Run Code Online (Sandbox Code Playgroud)

如果你有更多的字符(五个或六个IIRC),编译器实际上会创建一个哈希表来查找案例,所以这类似于使用a HashSet.