Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何超越这个正则表达式替代品?_C#_Regex_Optimization_String - Fatal编程技术网

C# 如何超越这个正则表达式替代品?

C# 如何超越这个正则表达式替代品?,c#,regex,optimization,string,C#,Regex,Optimization,String,经过大量测量,我已经在我们的一个windows服务中发现了一个热点,我想对其进行优化。我们正在处理可能包含多个连续空格的字符串,我们希望将其缩减为仅包含单个空格。我们使用静态编译的正则表达式执行此任务: private static readonly Regex regex_select_all_multiple_whitespace_chars = new Regex(@"\s+",RegexOptions.Compiled); 然后按如下方式使用: var cl

经过大量测量,我已经在我们的一个windows服务中发现了一个热点,我想对其进行优化。我们正在处理可能包含多个连续空格的字符串,我们希望将其缩减为仅包含单个空格。我们使用静态编译的正则表达式执行此任务:

private static readonly Regex 
    regex_select_all_multiple_whitespace_chars = 
        new Regex(@"\s+",RegexOptions.Compiled);
然后按如下方式使用:

var cleanString=
    regex_select_all_multiple_whitespace_chars.Replace(dirtyString.Trim(), " ");
这条线被调用了数百万次,并且被证明是相当密集的。我试图写些更好的东西,但我被难倒了。鉴于正则表达式的处理要求相当温和,肯定有更快的东西。使用指针进行
不安全的
处理会进一步加快速度吗

编辑:


谢谢你对这个问题的惊人回答。。。真想不到

只有一个建议,如果您的数据没有unicode空格,请使用
[\r\n]+
[\n]+
+
(如果只有空格),基本上将其限制为最小字符集。

目前,您正在用另一个空格替换单个空格。尝试匹配
\s{2,}
(或者类似的东西,如果您想替换单个换行符和其他字符)

无法使用正则表达式。例如:

private static string NormalizeWhitespace(string test)
{
    string trimmed = test.Trim();

    var sb = new StringBuilder(trimmed.Length);

    int i = 0;
    while (i < trimmed.Length)
    {
        if (trimmed[i] == ' ')
        {
            sb.Append(trimmed[i]);

            do { i++; } while (i < trimmed.Length && trimmed[i] == ' ');
        }

        sb.Append(trimmed[i]);

        i++;
    }

    return sb.ToString();
}

请注意,这仅通过一个非常简单的示例进行了测试,可以通过删除对
String.Trim
的调用进行进一步优化,并且仅用于说明正则表达式有时不是最佳答案。

这大约快三倍:

private static string RemoveDuplicateSpaces(string text) {
  StringBuilder b = new StringBuilder(text.Length);
  bool space = false;
  foreach (char c in text) {
    if (c == ' ') {
      if (!space) b.Append(c);
      space = true;
    } else {
      b.Append(c);
      space = false;
    }
  }
  return b.ToString();
}

我很好奇一个直接的实现会如何执行:

    static string RemoveConsecutiveSpaces(string input)
    {
        bool whiteSpaceWritten = false;
        StringBuilder sbOutput = new StringBuilder(input.Length);

        foreach (Char c in input)
        {
            if (c == ' ')
            {
                if (!whiteSpaceWritten)
                {
                    whiteSpaceWritten = true;
                    sbOutput.Append(c);
                }
            }
            else
            {
                whiteSpaceWritten = false;
                sbOutput.Append(c);
            }
        }

        return sbOutput.ToString();
    }

由于它是这样一个简单的表达式,将两个或多个空格替换为一个空格,因此请去掉Regex对象并自己硬编码替换内容(在C++/CLI中):

String^text=“一些要处理的文本”;
布尔空间=假;
//使下面的静态文件保持干净,而不是每次都重新分配它
System::Text::StringBuilder^output=gcnew System::Text::StringBuilder;
对于(int i=0,l=text->Length;i追加(文本[i]);
空格=假;
}
}
其他的
{
输出->追加(文本[i]);
如果(文本[i]='')
{
空格=真;
}
}
}
text=output->ToString();
这个怎么样

public string RemoveMultiSpace(string test)
{
var words = test.Split(new char[] { ' ' }, 
    StringSplitOptions.RemoveEmptyEntries);
return string.Join(" ", words);
}
使用NUnit运行测试用例:
测试时间以毫秒为单位

Regex Test time: 338,8885
RemoveMultiSpace Test time: 78,9335

阵列总是会更快

        public static string RemoveMultiSpace(string input)
    {
        var value = input;

        if (!string.IsNullOrEmpty(input))
        {
            var isSpace = false;
            var index = 0;
            var length = input.Length;
            var tempArray = new char[length];
            for (int i = 0; i < length; i++)
            {
                var symbol = input[i];
                if (symbol == ' ')
                {
                    if (!isSpace)
                    {
                        tempArray[index++] = symbol;
                    }
                    isSpace = true;
                }
                else
                {
                    tempArray[index++] = symbol;
                    isSpace = false;
                }
            }
            value = new string(tempArray, 0, index);
        }

        return value;
    }
publicstaticstringremovemultispace(字符串输入)
{
var值=输入;
如果(!string.IsNullOrEmpty(输入))
{
var-isSpace=false;
var指数=0;
变量长度=输入长度;
var tempArray=新字符[长度];
for(int i=0;i
您是经常在较小的字符串上运行它,还是在巨大的字符串上运行它strings@rob,它在大约10-40个字符长的字符串上运行,不确定C++/CLI是否正确!语法稍有不同,但将上述内容更改为C并不难。我刚刚打开了一个C++/CLI项目来测试代码(是的,我知道,但我必须使用它)。除了空白不仅仅是
'
,而且您不使用变量
trimemd
,这正是我要建议的+1@Rob丰塞卡·恩索尔,感谢你发现了这一点,这是最后一分钟的不完全改变我同意。对于关键点,快速测试表明我们可以做得更好。可能是因为代码更改与性能的比率非常好。在正则表达式中仅更改几个字符即可提高25%:)那太好了。快速浅层测试表明这比StringBuilder方法更快。更新:抱歉,起初我忘记了loop over RemoveMultiSpace方法。我认为测试结果看起来太糟糕了。;)它比使用StringBuilder快一点,但它也会创建一组临时字符串。您必须使用一些真实数据来尝试这些方法,以了解其对性能的影响。有人知道为什么这比StringBuilder方法快吗?@Heinzi:它在框架中使用优化(不安全模式或非托管)方法,比使用StringBuilder的托管代码快。尽管拆分联接做了一些额外的工作,但在某些情况下它的速度仍然更快,大约是正则表达式的三倍。Se我的答案(代码基本相同)。过度使用
var
关键字。为什么要将数组复制到另一个数组,而不是仅仅从tempArray创建字符串?@“{2,}”的性能几乎(在10%以内)与我的数据中建议的最佳方法一样好,回答得太好了!我选择了这个变体。使用for(int i…代替foreach,使用char c=text[i]可以提高一点速度。再次感谢大家。
public string RemoveMultiSpace(string test)
{
var words = test.Split(new char[] { ' ' }, 
    StringSplitOptions.RemoveEmptyEntries);
return string.Join(" ", words);
}
Regex Test time: 338,8885
RemoveMultiSpace Test time: 78,9335
private static readonly Regex regex_select_all_multiple_whitespace_chars =
   new Regex(@"\s+", RegexOptions.Compiled);

[Test]
public void Test()
{
    string startString = "A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      ";
    string cleanString;
    Trace.WriteLine("Regex Test start");
    int count = 10000;
    Stopwatch timer = new Stopwatch();
    timer.Start();
    for (int i = 0; i < count; i++)
    {
        cleanString = regex_select_all_multiple_whitespace_chars.Replace(startString, " ");
    }
    var elapsed = timer.Elapsed;
    Trace.WriteLine("Regex Test end");
    Trace.WriteLine("Regex Test time: " + elapsed.TotalMilliseconds);

    Trace.WriteLine("RemoveMultiSpace Test start");
    timer = new Stopwatch();
    timer.Start();
    for (int i = 0; i < count; i++)
    {
        cleanString = RemoveMultiSpace(startString);
    }
    elapsed = timer.Elapsed;
    Trace.WriteLine("RemoveMultiSpace Test end");
    Trace.WriteLine("RemoveMultiSpace Test time: " + elapsed.TotalMilliseconds);
}

public string RemoveMultiSpace(string test)
{
    var words = test.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    return string.Join(" ", words);
}
Cleaning file with about 30000 lines, 10 iterations
RegEx time elapsed: 608,0623
RemoveMultiSpace time elapsed: 239,2049
RemoveDuplicateSpaces time elapsed: 307,2044

Cleaning string, 10000 iterations:
A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      A B  C   D    E     F      
RegEx time elapsed: 590,3626
RemoveMultiSpace time elapsed: 159,4547
RemoveDuplicateSpaces time elapsed: 137,6816

Cleaning string, 10000 iterations:
A      B      C      D      E      F      A      B      C      D      E      F      A      B      C      D      E      F      A      B      C      D      E      F      A      B      C      D      E      F      A      B      C      D      E      F      A      B      C      D      E      F      A      B      C      D      E      F      
RegEx time elapsed: 290,5666
RemoveMultiSpace time elapsed: 64,6776
RemoveDuplicateSpaces time elapsed: 52,4732

        public static string RemoveMultiSpace(string input)
    {
        var value = input;

        if (!string.IsNullOrEmpty(input))
        {
            var isSpace = false;
            var index = 0;
            var length = input.Length;
            var tempArray = new char[length];
            for (int i = 0; i < length; i++)
            {
                var symbol = input[i];
                if (symbol == ' ')
                {
                    if (!isSpace)
                    {
                        tempArray[index++] = symbol;
                    }
                    isSpace = true;
                }
                else
                {
                    tempArray[index++] = symbol;
                    isSpace = false;
                }
            }
            value = new string(tempArray, 0, index);
        }

        return value;
    }