删除字符串中的额外间距[最快方式]

时间:2013-01-14 11:40:41

标签: c# regex performance

我需要删除字符串中的所有其他空格。 我使用正则表达式匹配字符串和匹配的字符串我替换其他一些。 为了更好地理解,请参阅以下示例:

3个输入字符串:

Hello, how are you?
Hello , how are  you?
Hello     ,     how    are   you    ?

这是3个字符串,应该与一个模式正则表达式匹配。 它看起来像这样:

Hello\s*,\s+how\s+are\s+you\s*?

它工作正常,但存在性能问题。 如果我有很多模式(~20k)并尝试执行每个模式,它运行得非常慢(3-5分钟)。

也许有更好的方法可以做到这一点? 例如,使用一些3d-party库?

UPD:伙计们,这个问题不是关于如何做到这一点。它是关于如何以最佳性能执行此操作。 :)


让我解释一下。主要目标是标记文本。 (用特殊符号替换某些标记)

例如,我有一个令牌“不错的尝试”。 然后我输入文字“这是很好的尝试”。 结果:“这是@ tokenizedtext @”,其中@ tokenizedtext @一些特殊符号。在这种情况下,这无关紧要。

接下来我有字符串“Mike说这是一个不错的尝试”。 结果应该是“Mike说它是@dragidtext @”。 我认为主要观点很明确。

所以我可以拥有很多代币。当我处理它时,我将我的令牌从“nice try”转换为模式“nice \ s + try”。并尝试用此模式输入文本替换。 它工作正常。但是如果在令牌中有更多空格并且还有标点符号那么我的正则表达式变得更大并且工作非常慢。

您是否有解决此问题的建议(技术或逻辑)?

6 个答案:

答案 0 :(得分:3)

我可以提出一些解决方案。

首先,避免使用静态Regex方法。创建它的实例(并存储它,不要为每个替换调用构造函数!),如果可能,使用RegexOptions.Compiled。它应该会提高你的表现。

其次,您可以尝试检查您的模式。我会做一些分析,但我目前在犹豫不决之间:

  

@ “(小于?= \ S)\ S +”

替换为空字符串或:

  

@“\ s +”

以空格作为替代品。你可以尝试这段代码:

var s = "Hello , how are  you?";
var pattern = @"\s+";
var regex = new Regex(pattern, RegexOptions.Compiled);
var replaced = regex.Replace(s, " ");

编辑:完成一些测量后,第二种模式似乎更快。我正在编辑我的样本以适应它。

编辑2 :我写了一个unsafe方法。它比这里介绍的其他更快,包括正则表达式,但正如这个词本身所说,它是不安全的。我不认为我编写的代码有任何问题,但我可能错了 - 所以,如果方法中存在错误,请再次检查。

static unsafe string TrimInternal(string input)
{
    var length = input.Length;
    var array = stackalloc char[length];
    fixed (char* fix = input)
    {
        var ptr = fix;
        var counter = 0;
        var lastWasSpace = false;
        while (*ptr != '\x0')
        {
            //Current char is a space?
            var isSpace = *ptr == ' ';
            //If it's a space but the last one wasn't
            //Or if it's not a space
            if (isSpace && !lastWasSpace || !isSpace)
                //Write into the result array
                array[counter++] = *ptr;
            //The last character (before the next loop) was a space
            lastWasSpace = isSpace;
            //Increase the pointer
            ptr++;
        }
        return new string(array, 0, counter);
    }
}

用法(使用/ unsafe编译):

var s = TrimInternal("Hello    , how       are     you?");

在发布版本中进行性能分析,优化,1000000次迭代:

  

我的上述解决方案与Regex:00:00:03.2130121

     

不安全的解决方案:00:00:00.2063467

答案 1 :(得分:1)

你正在使用一个非常复杂的正则表达式...简化正则表达式,这肯定会提高性能

使用\s+并将其替换为单个空格

答案 2 :(得分:1)

这可能适合你。它应该很快。请注意,它还会删除字符串末尾的空格;那可能不是你想要的......

using System;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(">{0}<", RemoveExtraSpaces("Hello, how are you?"));
            Console.WriteLine(">{0}<", RemoveExtraSpaces("Hello , how are  you?"));
            Console.WriteLine(">{0}<", RemoveExtraSpaces("Hello     ,     how    are   you    ?"));
        }

        public static string RemoveExtraSpaces(string text)
        {
            var buffer = new char[text.Length];
            bool isSpaced = false;
            int n = 0;

            foreach (char c in text)
            {
                if (c == ' ')
                {
                    isSpaced = true;
                }
                else
                {
                    if (isSpaced)
                    {
                        if ((c != ',') && (c != '?'))
                        {
                            buffer[n++] = ' ';
                        }

                        isSpaced = false;
                    }

                    buffer[n++] = c;
                }
            }

            return new string(buffer, 0, n);
        }
    }
}

答案 3 :(得分:1)

我自己的东西:

在字符串中找到WhiteSpacechar的所有位置;

private static IEnumerable<int> GetWhiteSpacePos(string input)
{

    int iPos = -1;
    while ((iPos = input.IndexOf(" ", iPos + 1, StringComparison.Ordinal)) > -1)
    {
        yield return iPos;
    }
}

GetWhiteSpacePos

中删除所有依次返回的空格
        string original_string = "Hello     ,     how    are   you    ?";

        var poss = GetWhiteSpacePos(original_string).ToList();
        int startPos;
        int endPos;
        StringBuilder builder = new StringBuilder(original_string);
        for (int i = poss.Count -1; i > 1; i--)
        {
            endPos = poss[i];
            while ((poss[i] == poss[i - 1] + 1) && i  > 1)
            {
                i--;
            }
            startPos = poss[i];
            if (endPos - startPos > 1)
            {
                builder.Remove(startPos, endPos - startPos);
            }

        }

        string new_string = builder.ToString();

答案 4 :(得分:0)

如果它只是SPACE的问题;

试试这个 资料来源:http://www.codeproject.com/Articles/10890/Fastest-C-Case-Insenstive-String-Replace

    private static string ReplaceEx(string original,
                string pattern, string replacement)
    {
        int count, position0, position1;
        count = position0 = position1 = 0;
        string upperString = original.ToUpper();
        string upperPattern = pattern.ToUpper();
        int inc = (original.Length / pattern.Length) *
                  (replacement.Length - pattern.Length);
        char[] chars = new char[original.Length + Math.Max(0, inc)];
        while ((position1 = upperString.IndexOf(upperPattern,
                                          position0)) != -1)
        {
            for (int i = position0; i < position1; ++i)
                chars[count++] = original[i];
            for (int i = 0; i < replacement.Length; ++i)
                chars[count++] = replacement[i];
            position0 = position1 + pattern.Length;
        }
        if (position0 == 0) return original;
        for (int i = position0; i < original.Length; ++i)
            chars[count++] = original[i];
        return new string(chars, 0, count);
    }

用法:

        string original_string = "Hello     ,     how    are   you    ?";
        while (original_string.Contains("  "))
        {
            original_string = ReplaceEx(original_string, "  ", " ");
        }

取代正则表达式:

string resultString = null;
try {
    resultString = Regex.Replace(subjectString, @"\s+", " ", RegexOption.Compiled);
} catch (ArgumentException ex) {
    // Syntax error in the regular expression
}

答案 5 :(得分:0)

嗯,这些问题确实给我们带来了麻烦。使用此代码,我确定您已根据自己的要求获得结果。此命令删除任何字符串之间的任何额外空格。

cleanString= Regex.Replace(originalString, @"\s", " ");

希望thar适合你。感谢。

因为这是一个单一的指令。它将利用更少的CPU资源,从而减少CPU时间,从而最终提高您的性能。因此A / C对我来说,这种方法在性能方面比较有效。