C# 删除字符串中的附加间距[最快方式]

C# 删除字符串中的附加间距[最快方式],c#,regex,performance,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个输入字符串:

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派对LIB

UPD:各位,这个问题不是关于如何做到这一点。它是关于如何以最佳性能完成此任务的。:)


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

例如,我有一个标记“很好的尝试”。 然后我输入文本“这是很好的尝试”。 结果:“这是@tokenizedtext@”,其中@tokenizedtext@包含一些特殊符号。在这种情况下没关系

接下来是“迈克说这是一次很好的尝试”。 结果应该是“Mike说这是一个@tokenizedtext@”。 我认为主要思想是明确的

所以我可以有很多代币。当我处理它时,我将令牌从“nice-try”转换为模式“nice\s+try”。并尝试用此模式替换输入文本。 它很好用。但是如果代币中有更多的空格和标点符号,那么我的正则表达式就变大了,运行速度也很慢


你对解决这个问题有什么建议(技术或逻辑)?

如果只是空间问题

试试这个 资料来源:

以以下方式替换正则表达式:

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

嗯,这些问题真的很困扰我们。使用这个代码,我相信你会得到你所要求的结果。此命令删除任何字符串之间的任何额外空格

cleanString= Regex.Replace(originalString, @"\s", " ");
希望他能为你工作。谢谢


因为这是一条指令。它将使用更少的CPU资源,从而减少CPU时间,从而最终提高性能。因此,A/C对我来说,这种方法在性能方面是最好的。

您使用的是一个非常复杂的正则表达式。简化正则表达式肯定会提高性能


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

我可以建议一些解决方案

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

第二,你可以试着回顾你的模式。我会做一些分析,但我目前还不确定:


@(?这可能适合您。它应该非常快。请注意,它还会删除字符串末尾的空格;这可能不是您想要的

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);
        }
    }
}
使用系统;
名称空间演示
{
班级计划
{
静态void Main(字符串[]参数)
{
Console.WriteLine(“>{0}{0}{0}我自己的东西:

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

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

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

如果您向我们展示完整的方法,我们可能会指出其中的慢点,但就目前情况而言,您只是给出了一些小片段,这些片段本身并没有真正的帮助。例如,您可能会错误地将20k中的每一个都与其他方法进行比较,而不是将其与一个成功的方法进行比较,这显然要慢得多!您有没有看看这个问题:-它详细解释了慢速c#regexp你想做什么?你的预期结果是什么?@alexi-请解释一下你期望得到什么样的输出在再次回复更新时,如果你不向我们展示你的代码,我们无法提高你的性能!这里不需要分组,或者只需要boldRegex。替换(原始字符串@“\s+”,“”);**bold**将完成此工作。它将所有空格转换为单个空格。您的方法效率低下且不可读。它大约比编译器正则表达式慢三倍。@Eve:我打赌您对调试生成而不是发布生成进行了计时。@MatthewWatson否。最糟糕的问题是
while
块。它创建了一个新的t实例在其中找到的每两个空格对应一个字符串。哦,对了,你是指用法块中的代码,而不是replaceX()的实现。@MatthewWatson该实现也有问题。它调用
ToUpper
两次,并创建两个新字符串(加上返回字符串)。此外,它还创建了
char
数组(我还没有试着读它的实际用途)。这都是开销。不幸的是,我不能使用
编译的
选项。(@AlexeiMalashkevich如果没有
编译
选项,速度会稍微慢一点,但速度还是相当快。我会尝试另一种方法。@AlexeiMalashkevich我写了一个方法,应该比其他建议的快。请尝试一下。看起来很有趣。我们会测试这个。现在是最好的答案。很抱歉延迟。我们会在一周内测试它一两个。
var s = "Hello , how are  you?";
var pattern = @"\s+";
var regex = new Regex(pattern, RegexOptions.Compiled);
var replaced = regex.Replace(s, " ");
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);
    }
}
var s = TrimInternal("Hello    , how       are     you?");
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);
        }
    }
}
private static IEnumerable<int> GetWhiteSpacePos(string input)
{

    int iPos = -1;
    while ((iPos = input.IndexOf(" ", iPos + 1, StringComparison.Ordinal)) > -1)
    {
        yield return iPos;
    }
}
        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();