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

时间:2011-03-10 15:27:53

标签: 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;
        }
}

根据我的探查器,代码在if(badChars.Contains(buffer[i]))花费了88%的时间,这样做的正确方法是什么,所以我不会造成可怕的缓慢?

6 个答案:

答案 0 :(得分:8)

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

将字符改为HashSet<char>

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

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

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

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

如果你有更多的字符(5或6个IIRC),编译器实际上会创建一个哈希表来查找案例,这与使用HashSet类似。

答案 1 :(得分:4)

使用switch语句可能会有更好的结果:

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

这应该由JIT编译器在运行时编译为快速代码。哎呀,编译器可能也会接近。您也不需要以这种方式调用方法。

答案 2 :(得分:0)

您可以将regular expressions用于应优化的内容。将文本读成字符串,然后在正则表达式中使用Replace和您的字符。

然而,你的代码对我来说也很好看,我猜正则表达式除了搜索你的文本之外也做不了什么...而且你需要在那里拿一个你不需要另外做的字符串选项。

答案 3 :(得分:0)

你可以通过检查读取字符来检查它的优化程度,使其成为

for (int i = index; i < index + count; i++){
  //etc
}

不知道这对你有多大帮助,你必须要分析你的真实世界应用程序来检查

答案 4 :(得分:0)

尝试将char[]转换为字符串,然后使用IndexOfAny

答案 5 :(得分:0)

您可以使用布尔数组

char[] badChars = { '\x00', '\x09', '\x0A', '\x10' };
char maxChar = badChars.Max();
Debug.Assert(maxChar < 256);
bool[] badCharsTable = new bool[maxChar + 1];

Array.ForEach(badChars, ch => badCharsTable[ch] = true);

并将badChars.Contains(...)替换为(ch < badCharsTable.Length && badCharsTable[ch])

编辑:最后有时间改进答案。