字符串操作性能和速度

时间:2012-08-21 12:12:45

标签: c# string optimization richtextbox

以下是我为RichTextBox派生类编写的三种方法,它是一种语法高亮显示。所有大写字母的richtextbox的当前行都有一个共享副本lcpy_strLine。这些方法的作用是什么;

  • ColorInsideTwoChars 为指定颜色指定两个指定字符之间的字符。防爆。对于当前行中的所有括号组,ColorInsideTwoChar("(", ")", Color.Green)会为两个括号绿色之间的所有字符着色

  • ColorTilNoNumFromChar 颜色,来自指定字符,所有字符都是数字,例如。遇到G后,ColorTilNoNumFromChar("G", Color.Red)将为所有数字着色,红色(包括G)

  • ColorCharIfNotFollowedByLetter 为指定字符添加颜色(如果后面没有字母)。防爆。 ColorCharIfNotFollowedByLetter("x", Color.Orange)将为所有X后面没有字母的橙色着色

我的问题是,是否有更快的方法来执行这些方法。它们看起来很丑陋,我认为这些方法肯定更简单,更美观。有什么建议?我问,因为这些方法是在几千行文件的每一行上运行的,而且非常慢。我需要加快速度。我可以尝试用不同的方式重写几次,或者我可以让一些聪明人尝试让我朝着正确的方向前进。

    private void ColorInsideTwoChars(String car1, String car2, Color clr)
    {
        int indx1 = 0;
        int indx2 = 0;
        while ((indx1 = lcpy_strLine.IndexOf(car1, indx1)) != -1
                && (indx2 = lcpy_strLine.IndexOf(car2, indx2)) != -1
                && indx1 < indx2)
        {
            SelectionStart = m_nLineStart + indx1;
            SelectionLength = (indx2 - indx1) + 1;
            SelectionColor = clr;
            indx1 = ++indx2;
        }
    }
    private void ColorTilNoNumFromChar(String car, Color clr)
    {
        int indx1 = 0;
        while ((indx1 = lcpy_strLine.IndexOf(car, indx1)) != -1)
        {
            int j = 0;
            for (j = indx1 + 1; j < m_nLineLength; j++)
            {
                if (!Char.IsDigit(lcpy_strLine[j]))
                    break;
            }
            SelectionStart = m_nLineStart + indx1;
            SelectionLength = j - indx1;
            SelectionColor = clr;
            indx1 = j;
        }
    }
    private void ColorCharIfNotFollowedByLetter(String car, Color clr)
    {
        int indx1 = 0;
        while ((indx1 = lcpy_strLine.IndexOf(car, indx1)) != -1 &&
            indx1 + 1 < m_nLineLength)
        {
            SelectionStart = m_nLineStart + indx1;
            SelectionLength = 1;
            if (!Char.IsLetter(lcpy_strLine[lcpy_strLine.IndexOf(car) + 1]))
                SelectionColor = clr;
            else
                SelectionColor = Color.Black;
            ++indx1;
        }
    }

2 个答案:

答案 0 :(得分:0)

对于ColorInsideTwoChar(),请注意,即使它们是嵌套的,您也会对括号中的内容进行着色,从而使其更多一次。如果括号(或一般的这些字符)不匹配怎么办?也许找到开头的字符,然后把它关闭char并将颜色之间的所有内容染色?然后从你关闭char的位置开始搜索,并寻找下一个开放的一个..而且,我只会在换行时调用它,不知道你的想法是什么;)并且可能只在RichBox的可见部分开始,然后在后台为其余颜色着色?

for (j = indx1 + 1; j < m_nLineLength; j++)
        {
            if (!Char.IsDigit(lcpy_strLine[j]))
                break;
        }

我会换掉

while (Char.IsDigit(lcpy_strLine[++j])) ;

虽然它可能或多或少相同......

但我认为你应该等待一些更专业的答案,这可能是一些更优雅的方法。

另外,也许,在方法开头找到所有想要的字符,并将它们放入数组中,会比一次又一次地查找它们更快?

对于较大的文件块,这可能比单行更快......

答案 1 :(得分:0)

1] ColorInsideTwoChars ColorInsideTwoChars将指定颜色的两个指定字符之间的字符着色。防爆。对于当前行中的所有括号组,ColorInsideTwoChar("(", ")", Color.Green)会为两个括号绿色之间的所有字符着色

这个函数的坏处是IndexOf函数。如果不是更差,你的表现将是O(n ^ 2)。你应该做的是:

仅读取一次,并将大括号的所有位置存储到新列表中。像这样:

var leftList = new List<int>();
var rightList = new List<int>();
for(var i = 0; i < str.Length; i++)
{
   if(str[i] == car1) leftList.Add(i);
   if(str[i] == car2) rightList.Add(i);
}

if(leftList.Length != rightList.Length) { /*possible error or no?!*/ }
//now start going like this:
int index1 = leftList.Length - 1;
int index2 = 0;
while(index1 >= 0 && index2 < rightList.Length)
{
  //do your coloring here.
  index1--;
  index2++;
}

这比你现在的要快得多。虽然你会交易一点记忆,但没关系。我建议你把那些列表作为类的变量而不是方法。还要确保它们通常在默认情况下足够大,因此不会发生分配。在下一次迭代中,使用Clear()

2] ColorTilNoNumFromChar颜色,来自指定字符,所有字符都是数字,例如。遇到G后,ColorTilNoNumFromChar("G", Color.Red)将为所有数字着色,红色(包括G)

我不会这样写,但更长一点:

for(var i = 0; i < str.Length; i++)
{
   if(str[i] == "G")
   {
      int selectionStart = i + 1;
      int selectionLength = -1;
      for(var k = i + 1; k < str.Length; k++)
      {
         if(IsDigit(str[i]))
         {
            if(selectionLength == -1) selectionLength = 0;
            selectionLength++;
         } else break;
      }
      //look if selectionLength is not -1
      i = k;//advance.
   }
}

从你上一篇文章开始,你也有IndexOf可以被淘汰,从而产生更多的表现。

如果你分别运行这些方法(每个方法),那么它就是nono。你应该立刻做所有事情(会更难,但要快得多)。