ChatGPT解决这个技术问题 Extra ChatGPT

从字符串中删除所有空格的有效方法?

我正在调用 REST API 并收到返回的 XML 响应。它返回一个工作区名称列表,我正在编写一个快速的 IsExistingWorkspace() 方法。由于所有工作区都由没有空格的连续字符组成,我假设找出特定工作区是否在列表中的最简单方法是删除所有空格(包括换行符)并执行此操作(XML 是从网络接收的字符串要求):

XML.Contains("<name>" + workspaceName + "</name>");

我知道它区分大小写,我依赖它。我只需要一种有效删除字符串中所有空格的方法。我知道 RegEx 和 LINQ 可以做到,但我对其他想法持开放态度。我主要关心的是速度。

使用正则表达式解析 XML 几乎和 parsing HTML with regex 一样糟糕。
@henk holterman;请参阅下面的答案,正则表达式似乎并不是在所有情况下都是最快的。
正则表达式似乎根本不是最快的。我总结了从字符串中删除空格的许多不同方法的结果。摘要在下面的答案中 - stackoverflow.com/a/37347881/582061

N
NearHuscarl

这是我知道的最快的方法,即使你说你不想使用正则表达式:

Regex.Replace(XML, @"\s+", "");

在评论中注明@hypehuman,如果您打算多次执行此操作,请创建并存储一个 Regex 实例。这将节省每次构建它的开销,这比您想象的要昂贵。

private static readonly Regex sWhitespace = new Regex(@"\s+");
public static string ReplaceWhitespace(string input, string replacement) 
{
    return sWhitespace.Replace(input, replacement);
}

我可以使用正则表达式,我只是不确定它是否是最快的方法。
那不应该是Regex.Replace(XML, @"\s+", "")吗?
如果您打算多次执行此操作,请创建并存储一个 Regex 实例。这将节省每次构建它的开销,这比您想象的要昂贵。 private static readonly Regex sWhitespace = new Regex(@"\s+"); public static string ReplaceWhitespace(string input, string replacement) { return sWhitespace.Replace(input, replacement); }
到目前为止,使用经过测试的拆分/连接组合是最快的,请参阅下面的 KernowCode 答案。
对于那些不熟悉 RegEx 并正在寻找有关此表达式含义的解释的人,\s 表示“匹配任何空白标记”,而 + 表示“匹配一个或多个正在进行的标记”。如果您想尝试一下,RegExr 也是一个很好的网站,可以用来练习编写 RegEx 表达式。
P
Peter Mortensen

我有一个没有正则表达式的替代方法,它似乎表现得很好。这是 Brandon Moretz 回答的延续:

 public static string RemoveWhitespace(this string input)
 {
    return new string(input.ToCharArray()
        .Where(c => !Char.IsWhiteSpace(c))
        .ToArray());
 }

我在一个简单的单元测试中对其进行了测试:

[Test]
[TestCase("123 123 1adc \n 222", "1231231adc222")]
public void RemoveWhiteSpace1(string input, string expected)
{
    string s = null;
    for (int i = 0; i < 1000000; i++)
    {
        s = input.RemoveWhitespace();
    }
    Assert.AreEqual(expected, s);
}

[Test]
[TestCase("123 123 1adc \n 222", "1231231adc222")]
public void RemoveWhiteSpace2(string input, string expected)
{
    string s = null;
    for (int i = 0; i < 1000000; i++)
    {
        s = Regex.Replace(input, @"\s+", "");
    }
    Assert.AreEqual(expected, s);
}

对于 1,000,000 次尝试,第一个选项(没有 regexp)在不到一秒的时间内运行(在我的机器上为 700 毫秒),第二个需要 3.5 秒。


.ToCharArray() 不是必需的;您可以直接在字符串上使用 .Where()
只是要注意这里。正则表达式较慢......在小字符串上!如果您说您拥有美国税法卷的数字化版本(约百万字?),经过几次迭代,到目前为止,Regex 才是王道!它不是什么更快,而是在什么情况下应该使用什么。你在这里只证明了一半的方程式。 -1,直到您证明测试的后半部分,以便答案提供更多关于何时应该使用的信息。
@ppumkin 他要求一次性删除空格。不是其他处理的多次迭代。我不会在一篇关于基准测试文本处理的扩展文章中介绍这个单通道空格删除。
您说这次它更喜欢不使用正则表达式,但没有说明原因。
@ProgramFOX,在另一个问题(不容易找到)中,我注意到至少在某些查询中,使用 ToCharArray 比直接在字符串上使用 .Where() 更快。这与每个迭代步骤中 IEnumerable<> 的开销有关,并且 ToCharArray 非常高效(块复制)并且编译器优化了数组的迭代。为什么存在这种差异,没有人能够解释我,但在删除 ToCharArray() 之前测量。
R
Rudey

尝试 C# 中字符串的替换方法。

XML.Replace(" ", string.Empty);

不删除制表符或换行符。如果我现在进行多次删除,我正在对字符串进行多次传递。
像 slandau 和 Henk 的回答那样,不删除所有空格而投反对票。
@MattSach 为什么不删除所有空格?
@Zapnologica 它只是替换空格字符。 OP 也要求替换换行符(它们是“空白”字符,即使它们不是空格字符)。
在回答之前拒绝不阅读 OP 问题:所有空格,而不仅仅是空格
k
kernowcode

我的解决方案是使用拆分和加入,它的速度非常快,实际上是这里的最佳答案中最快的。

str = string.Join("", str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));

带有空格的简单字符串上的 10,000 次循环的计时值 inc 新行和制表符

拆分/加入 = 60 毫秒

linq chararray = 94 毫秒

正则表达式 = 437 毫秒

通过将其包装在方法中以赋予其意义来改进这一点,并在我们使用它时使其成为扩展方法......

public static string RemoveWhitespace(this string str) {
    return string.Join("", str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));
}

我真的很喜欢这个解决方案,自 LINQ 之前的日子以来,我一直在使用类似的解决方案。实际上,我对 LINQ 的性能印象深刻,对正则表达式有些惊讶。也许代码不像正则表达式那样优化(例如,您必须缓存正则表达式对象)。但问题的症结在于数据的“质量”会很重要。也许对于长字符串,正则表达式将优于其他选项。这将是一个有趣的基准测试...... :-)
default(string[]) == 如何列出所有空白字符?我看到它工作,但我不明白如何?
@kernowcode您的意思是string[]char[]的2个重载之间的歧义?您只需指定您想要的,例如:string.Join("", str.Split((string[])null, StringSplitOptions.RemoveEmptyEntries));。在这种情况下,这实际上就是您对 default 的调用,因为它也返回 null:它帮助编译器决定选择哪个重载。因此我的评论是因为您的评论中的陈述“拆分需要一个有效的数组并且 null 不会做......”是错误的。没什么大不了的,只是觉得值得一提,因为 Jake Drew 询问了这是如何工作的。 +1 为您的回答
好主意……但我会这样做:string.Concat("H \ne llo Wor ld".Split())
michaelkrisper 解决方案非常易读。我做了一个测试,对于同一字符串的 10,000 次迭代,'split/join'(162 毫秒)的性能优于 'split/concat'(180 毫秒)。
S
Stian Standahl

Henks answer 的基础上,我用他的答案创建了一些测试方法,并添加了一些更优化的方法。我发现结果因输入字符串的大小而异。因此,我用两个结果集进行了测试。在最快的方法中,链接源有更快的方法。但是,由于它被认为是不安全的,所以我把它省略了。

长输入字符串结果:

InPlaceCharArray:2021 毫秒(Sunsetquest 的答案)-(原始来源)字符串拆分然后加入:4277 毫秒(Kernowcode 的答案)字符串阅读器:使用本机 char.IsWhitespace 的 6082 毫秒 LINQ:7357 毫秒 LINQ:7746 毫秒(Henk 的答案)ForLoop:32320 毫秒 RegexCompiled :37157 毫秒正则表达式:42940 毫秒

短输入字符串结果:

InPlaceCharArray:108 毫秒(Sunsetquest 的答案)-(原始来源)字符串拆分然后加入:294 毫秒(Kernowcode 的答案)字符串阅读器:327 毫秒 ForLoop:343 毫秒使用本机 char.IsWhitespace 的 LINQ:624 毫秒 LINQ:645 毫秒(Henk 的答案)RegexCompiled :1671 毫秒正则表达式:2599 毫秒

代码:

public class RemoveWhitespace
{
    public static string RemoveStringReader(string input)
    {
        var s = new StringBuilder(input.Length); // (input.Length);
        using (var reader = new StringReader(input))
        {
            int i = 0;
            char c;
            for (; i < input.Length; i++)
            {
                c = (char)reader.Read();
                if (!char.IsWhiteSpace(c))
                {
                    s.Append(c);
                }
            }
        }

        return s.ToString();
    }

    public static string RemoveLinqNativeCharIsWhitespace(string input)
    {
        return new string(input.ToCharArray()
            .Where(c => !char.IsWhiteSpace(c))
            .ToArray());
    }

    public static string RemoveLinq(string input)
    {
        return new string(input.ToCharArray()
            .Where(c => !Char.IsWhiteSpace(c))
            .ToArray());
    }

    public static string RemoveRegex(string input)
    {
        return Regex.Replace(input, @"\s+", "");
    }

    private static Regex compiled = new Regex(@"\s+", RegexOptions.Compiled);
    public static string RemoveRegexCompiled(string input)
    {
        return compiled.Replace(input, "");
    }

    public static string RemoveForLoop(string input)
    {
        for (int i = input.Length - 1; i >= 0; i--)
        {
            if (char.IsWhiteSpace(input[i]))
            {
                input = input.Remove(i, 1);
            }
        }
        return input;
    }

    public static string StringSplitThenJoin(this string str)
    {
        return string.Join("", str.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries));
    }

    public static string RemoveInPlaceCharArray(string input)
    {
        var len = input.Length;
        var src = input.ToCharArray();
        int dstIdx = 0;
        for (int i = 0; i < len; i++)
        {
            var ch = src[i];
            switch (ch)
            {
                case '\u0020':
                case '\u00A0':
                case '\u1680':
                case '\u2000':
                case '\u2001':
                case '\u2002':
                case '\u2003':
                case '\u2004':
                case '\u2005':
                case '\u2006':
                case '\u2007':
                case '\u2008':
                case '\u2009':
                case '\u200A':
                case '\u202F':
                case '\u205F':
                case '\u3000':
                case '\u2028':
                case '\u2029':
                case '\u0009':
                case '\u000A':
                case '\u000B':
                case '\u000C':
                case '\u000D':
                case '\u0085':
                    continue;
                default:
                    src[dstIdx++] = ch;
                    break;
            }
        }
        return new string(src, 0, dstIdx);
    }
}

测试:

[TestFixture]
public class Test
{
    // Short input
    //private const string input = "123 123 \t 1adc \n 222";
    //private const string expected = "1231231adc222";

    // Long input
    private const string input = "123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222123 123 \t 1adc \n 222";
    private const string expected = "1231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc2221231231adc222";

    private const int iterations = 1000000;

    [Test]
    public void RemoveInPlaceCharArray()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveInPlaceCharArray(input);
        }

        stopwatch.Stop();
        Console.WriteLine("InPlaceCharArray: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveStringReader()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveStringReader(input);
        }

        stopwatch.Stop();
        Console.WriteLine("String reader: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveLinqNativeCharIsWhitespace()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveLinqNativeCharIsWhitespace(input);
        }

        stopwatch.Stop();
        Console.WriteLine("LINQ using native char.IsWhitespace: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveLinq()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveLinq(input);
        }

        stopwatch.Stop();
        Console.WriteLine("LINQ: " + stopwatch.ElapsedMilliseconds + " ms");
        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveRegex()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveRegex(input);
        }

        stopwatch.Stop();
        Console.WriteLine("Regex: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveRegexCompiled()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveRegexCompiled(input);
        }

        stopwatch.Stop();
        Console.WriteLine("RegexCompiled: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [Test]
    public void RemoveForLoop()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.RemoveForLoop(input);
        }

        stopwatch.Stop();
        Console.WriteLine("ForLoop: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }

    [TestMethod]
    public void StringSplitThenJoin()
    {
        string s = null;
        var stopwatch = Stopwatch.StartNew();
        for (int i = 0; i < iterations; i++)
        {
            s = RemoveWhitespace.StringSplitThenJoin(input);
        }

        stopwatch.Stop();
        Console.WriteLine("StringSplitThenJoin: " + stopwatch.ElapsedMilliseconds + " ms");

        Assert.AreEqual(expected, s);
    }
}

编辑:从 Kernowcode 测试了一个不错的衬里。


F
Foxfire

只是一个替代方案,因为它看起来相当不错:) - 注意:Henks answer 是其中最快的。

input.ToCharArray()
 .Where(c => !Char.IsWhiteSpace(c))
 .Select(c => c.ToString())
 .Aggregate((a, b) => a + b);

"This is a simple Test" 上测试 1,000,000 个循环

此方法 = 1.74 秒
正则表达式 = 2.58 秒
new String (Henks) = 0.82 秒


为什么这被否决了?它完全可以接受,符合要求,比 RegEx 选项运行得更快并且可读性强?
因为它可以写得更短: new string(input.Where(c => !Char.IsWhiteSpace(c)).ToArray());
可能是真的 - 但答案仍然存在,可读,比正则表达式更快并产生所需的结果。许多其他答案都在这个答案之后......因此投反对票没有意义。
“0.82”有单位吗?或者它是一个相对的衡量标准(82%)?您可以编辑答案以使其更清楚吗?
S
SunsetQuest

我在 Felipe Machado 的 CodeProject 上找到了 a nice write-up on this(在 Richard Robertson 的帮助下)

他测试了十种不同的方法。这是最快的安全版本...

public static string TrimAllWithInplaceCharArray(string str) {

    var len = str.Length;
    var src = str.ToCharArray();
    int dstIdx = 0;

    for (int i = 0; i < len; i++) {
        var ch = src[i];

        switch (ch) {

            case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':

            case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':

            case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':

            case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':

            case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

            default:
                src[dstIdx++] = ch;
                break;
        }
    }
    return new string(src, 0, dstIdx);
}

还有最快的不安全版本......(Sunsetquest 5/26/2021 的一些改进)

public static unsafe void RemoveAllWhitespace(ref string str)
{
    fixed (char* pfixed = str)
    {
        char* dst = pfixed;
        for (char* p = pfixed; *p != 0; p++)
        {
            switch (*p)
            {
                case '\u0020': case '\u00A0': case '\u1680': case '\u2000': case '\u2001':
                case '\u2002': case '\u2003': case '\u2004': case '\u2005': case '\u2006':
                case '\u2007': case '\u2008': case '\u2009': case '\u200A': case '\u202F':
                case '\u205F': case '\u3000': case '\u2028': case '\u2029': case '\u0009':
                case '\u000A': case '\u000B': case '\u000C': case '\u000D': case '\u0085':
                continue;

                default:
                    *dst++ = *p;
                    break;
            }
        }

        uint* pi = (uint*)pfixed;
        ulong len = ((ulong)dst - (ulong)pfixed) >> 1;
        pi[-1] = (uint)len;
        pfixed[len] = '\0';
    }
}

Stian Standahl 在 Stack Overflow 上也有一些不错的 independent benchmarks,它还展示了 Felipe 的函数如何比下一个最快的函数快 300%。另外,对于我修改的那个,我使用了 this 技巧。


我试过把它翻译成 C++,但有点卡住了。任何想法为什么我的端口可能会失败? stackoverflow.com/questions/42135922/…
我无法抗拒。查看您所引用文章的评论部分。你会发现我是“篮子软件”。他和他一起为此工作了一段时间。当这个问题再次出现时,我完全忘记了这一点。感谢美好的回忆。 :)
如果您只想删除额外的 WS 怎么办?这个 stackoverflow.com/questions/17770202/… 模组怎么样?
最快的速度有点慢;-) 字符串作为容器在这里表现更好(在应用程序中 4:15 到 3:55 => 8.5% 少,但是当左字符串 3:30 => 21.4% 少并且分析器显示大约 50% 花费在这种方法)。因此,与此处使用的(慢)数组转换相比,实际的字符串应该快 40% 左右。
原来的字符串会被不安全的版本改变!
P
Peter Mortensen

如果您需要出色的性能,则在这种情况下应避免使用 LINQ 和正则表达式。我做了一些性能基准测试,似乎如果你想从字符串的开头和结尾去除空格, string.Trim() 是你的终极功能。

如果您需要从字符串中删除所有空格,以下方法在此处发布的所有方法中效果最快:

    public static string RemoveWhitespace(this string input)
    {
        int j = 0, inputlen = input.Length;
        char[] newarr = new char[inputlen];

        for (int i = 0; i < inputlen; ++i)
        {
            char tmp = input[i];

            if (!char.IsWhiteSpace(tmp))
            {
                newarr[j] = tmp;
                ++j;
            }
        }
        return new String(newarr, 0, j);
    }

我很想知道你的基准测试的细节——不是我怀疑,而是我对 Linq 所涉及的开销感到好奇。有多糟糕?
我没有重新运行所有的测试,但我记得这么多:涉及 Linq 的所有东西都比没有它的任何东西慢很多。如果使用 Linq,所有对字符串 / 字符函数和构造函数的巧妙使用都不会产生百分比差异。
P
Peter Mortensen

正则表达式是多余的;只需在字符串上使用扩展名(感谢 Henk)。这是微不足道的,应该是框架的一部分。无论如何,这是我的实现:

public static partial class Extension
{
    public static string RemoveWhiteSpace(this string self)
    {
        return new string(self.Where(c => !Char.IsWhiteSpace(c)).ToArray());
    }
}

这基本上是一个不必要的答案(正则表达式是矫枉过正,但比给定的解决方案更快 - 它已经被接受了吗?)
如何在字符串上使用 Linq 扩展方法?除了 System.Linq 之外,我不知道使用哪种方式
好的看起来这在 PCL 中不可用,IEnumerable<char>在 Microsoft String implementation 中是有条件的...而且我使用的是不支持此功能的 Profile259 :)
@GGirard 字符串是 char 的集合,因此 linq 应该默认工作。
P
Peter Mortensen

这是 RegEx 解决方案的简单线性替代方案。我不确定哪个更快;您必须对其进行基准测试。

static string RemoveWhitespace(string input)
{
    StringBuilder output = new StringBuilder(input.Length);

    for (int index = 0; index < input.Length; index++)
    {
        if (!Char.IsWhiteSpace(input, index))
        {
            output.Append(input[index]);
        }
    }
    return output.ToString();
}

u
user1325543

我需要用空格替换字符串中的空格,而不是重复的空格。例如,我需要转换如下内容:

"a b   c\r\n d\t\t\t e"

"a b c d e"

我使用了以下方法

private static string RemoveWhiteSpace(string value)
{
    if (value == null) { return null; }
    var sb = new StringBuilder();

    var lastCharWs = false;
    foreach (var c in value)
    {
        if (char.IsWhiteSpace(c))
        {
            if (lastCharWs) { continue; }
            sb.Append(' ');
            lastCharWs = true;
        }
        else
        {
            sb.Append(c);
            lastCharWs = false;
        }
    }
    return sb.ToString();
}

d
dtb

我假设您的 XML 响应如下所示:

var xml = @"<names>
                <name>
                    foo
                </name>
                <name>
                    bar
                </name>
            </names>";

处理 XML 的最佳方式是使用 XML 解析器,例如 LINQ to XML:

var doc = XDocument.Parse(xml);

var containsFoo = doc.Root
                     .Elements("name")
                     .Any(e => ((string)e).Trim() == "foo");

一旦我验证了特定的 标记具有正确的值,我就完成了。解析文档不会有一些开销吗?
当然,它有一些开销。但它有正确的好处。例如,基于正则表达式的解决方案要正确得多。如果您确定 LINQ to XML 解决方案太慢,您总是可以用更快的方法替换它。但是,在您知道正确的实现太慢之前,您应该避免寻找最有效的实现。
这将在我雇主的后端服务器中运行。轻量级是我正在寻找的。我不想要“正常工作”但最佳的东西。
LINQ to XML 是在 .NET 中正确使用 XML 的最轻量级方法之一
T
Tarik BENARAB

我们可以用:

    public static string RemoveWhitespace(this string input)
    {
        if (input == null)
            return null;
        return new string(input.ToCharArray()
            .Where(c => !Char.IsWhiteSpace(c))
            .ToArray());
    }

这与Henk上面的答案几乎完全相同。唯一的区别是您检查 null
是的,检查空值很重要
也许这应该只是对他的回答的评论。不过,我很高兴你提出来。我不知道可以在空对象上调用扩展方法。
K
Kewin Remy

使用 Linq,您可以这样编写一个可读的方法:

    public static string RemoveAllWhitespaces(this string source)
    {
        return string.IsNullOrEmpty(source) ? source : new string(source.Where(x => !char.IsWhiteSpace(x)).ToArray());
    }

l
larsemil

我想很多人来这里是为了消除空间。 :

string s = "my string is nice";
s = s.replace(" ", "");

这样做的问题是,一个空间可以用许多不同的方式来写,正如其他答案中提到的那样。此替换适用于 90%~ 左右的情况。
F
Fred

这是另一个变体:

public static string RemoveAllWhitespace(string aString)
{
  return String.Join(String.Empty, aString.Where(aChar => aChar !Char.IsWhiteSpace(aChar)));
}

与大多数其他解决方案一样,我没有进行详尽的基准测试,但这对于我的目的来说已经足够好了。


h
hvanbrug

我发现不同的结果是正确的。我正在尝试用单个空格替换所有空格,并且正则表达式非常慢。

return( Regex::Replace( text, L"\s+", L" " ) );

对我来说最有效的(在 C++ cli 中)是:

String^ ReduceWhitespace( String^ text )
{
  String^ newText;
  bool    inWhitespace = false;
  Int32   posStart = 0;
  Int32   pos      = 0;
  for( pos = 0; pos < text->Length; ++pos )
  {
    wchar_t cc = text[pos];
    if( Char::IsWhiteSpace( cc ) )
    {
      if( !inWhitespace )
      {
        if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );
        inWhitespace = true;
        newText += L' ';
      }
      posStart = pos + 1;
    }
    else
    {
      if( inWhitespace )
      {
        inWhitespace = false;
        posStart = pos;
      }
    }
  }

  if( pos > posStart ) newText += text->Substring( posStart, pos - posStart );

  return( newText );
}

我首先通过单独替换每个字符来尝试上述例程,但不得不切换到为非空格部分执行子字符串。应用于 1,200,000 字符串时:

上述例程在 25 秒内完成

上面的套路+95秒的单独字符替换

正则表达式在 15 分钟后中止。