Maneira eficiente de remover todo o espaço em branco da String?


358

Estou chamando uma API REST e estou recebendo uma resposta XML de volta. Ele retorna uma lista dos nomes de um espaço de trabalho e estou escrevendo um IsExistingWorkspace()método rápido . Como todos os espaços de trabalho consistem em caracteres contíguos sem espaço em branco, estou assumindo que a maneira mais fácil de descobrir se um espaço de trabalho específico está na lista é remover todos os espaços em branco (incluindo novas linhas) e fazer isso (XML é a string recebida da Web solicitação):

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

Eu sei que diferencia maiúsculas de minúsculas e estou confiando nisso. Eu só preciso de uma maneira de remover todo o espaço em branco em uma string de forma eficiente. Eu sei que o RegEx e o LINQ podem fazer isso, mas estou aberto a outras idéias. Estou principalmente preocupado apenas com velocidade.


6
A análise de XML com regex é quase tão ruim quanto a análise de HTML com regex .
dtb

3
@henk holterman; Veja minha resposta abaixo, regexp não parece ser o mais rápido em todos os casos.
Henk J Meulekamp

Regex não parece ser o mais rápido. Resumi os resultados de várias maneiras diferentes para remover o espaço em branco de uma string. O resumo está em uma resposta abaixo - stackoverflow.com/a/37347881/582061
Stian Standahl

Respostas:


616

Esta é a maneira mais rápida que eu conheço, mesmo que você tenha dito que não queria usar expressões regulares:

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

11
Eu poderia usar uma expressão regular, mas não tenho certeza se é a maneira mais rápida.
Corey Ogburn

11
Eu tenho certeza que é. No mínimo, nos bastidores, você deve verificar todos os personagens, e isso é apenas uma pesquisa linear.
Slandau

19
Não deveria ser Regex.Replace(XML, @"\s+", "")?
Jan-Peter Vos

61
Se você planeja fazer isso mais de uma vez, crie e armazene uma instância Regex. Isso economizará a sobrecarga de construí-lo sempre, o que é mais caro do que você imagina. private static readonly Regex sWhitespace = new Regex(@"\s+"); public static string ReplaceWhitespace(string input, string replacement) { return sWhitespace.Replace(input, replacement); }
Hypehuman

10
Para quem é novo no RegEx e procura uma explicação sobre o significado dessa expressão, \ssignifica "corresponder a qualquer token de espaço em branco" e +significa "corresponder a um ou mais do token de processo". Além disso, o RegExr é um ótimo site para praticar a escrita de expressões RegEx, se você quiser experimentar.
JRH

181

Eu tenho uma maneira alternativa sem regexp, e parece ter um bom desempenho. É uma continuação da resposta de Brandon Moretz:

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

Eu testei em um teste de unidade simples:

[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);
}

Para 1.000.000 de tentativas, a primeira opção (sem regexp) é executada em menos de um segundo (700 ms na minha máquina) e a segunda leva 3,5 segundos.


40
.ToCharArray()não é necessário; você pode usar .Where()diretamente em uma string.
ProgramFOX 01/01

10
Apenas para observar aqui. Regex é mais lento ... em pequenas cordas! Se você diz que possui uma versão digitalizada de um volume sobre a legislação tributária dos EUA (~ milhões de palavras?), Com algumas iterações, a Regex é rei, de longe! Não é o que é mais rápido, mas o que deve ser usado em que circunstâncias. Você provou apenas metade da equação aqui. -1 até você provar a segunda metade do teste, para que a resposta forneça mais informações sobre quando o que deve ser usado.
Piotr Kula

17
@ppumkin Ele pediu a remoção de um único passe do espaço em branco. Não são várias iterações de outro processamento. Não vou transformar essa remoção de espaço em branco de passagem única em uma postagem extendida sobre o processamento de texto de benchmarking.
Henk J Meulekamp

11
Você disse que preferia não usar regex desta vez, mas não disse o porquê.
Piotr Kula

2
@ProgramFOX, em uma pergunta diferente (não consigo encontrá-lo facilmente), notei que pelo menos em algumas consultas, o uso ToCharArrayé mais rápido do que o uso .Where()direto na string. Isso tem algo a ver com a sobrecarga na IEnumerable<>etapa de cada iteração, e com a ToCharArrayeficiência (cópia em bloco) e o compilador otimiza a iteração sobre as matrizes. Por que essa diferença existe, ninguém foi capaz de me explicar, mas meça antes de remover ToCharArray().
Abel

87

Tente o método de substituição da string em C #.

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

28
Não remove guias ou novas linhas. Se eu fizer várias remoções agora, estou fazendo várias passagens sobre a string.
Corey Ogburn

11
Voto negativo por não remover todo o espaço em branco, como fazem as respostas de slandau e Henk.
precisa

@MattSach por que não remove TODOS os espaços em branco?
Zapnologica

4
@Zapnologica Ele está substituindo apenas caracteres de espaço. O OP também solicitou a substituição de novas linhas (que são caracteres de "espaço em branco", mesmo que não sejam caracteres de espaço).
precisa

75

Minha solução é usar o Split and Join e é surpreendentemente rápido, na verdade, a mais rápida das principais respostas aqui.

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

Horários para 10.000 loop em cadeia simples com espaço em branco, incluindo novas linhas e tabulações

  • divisão / união = 60 milissegundos
  • linq chararray = 94 milissegundos
  • regex = 437 milissegundos

Para melhorar isso, envolva-o no método para lhe dar significado e também faça dele um método de extensão enquanto estamos nisso ...

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

3
Eu realmente gosto dessa solução, uso uma similar desde os dias anteriores ao LINQ. Na verdade, estou impressionado com o desempenho dos LINQs e um tanto surpreso com o regex. Talvez o código não tenha sido o melhor possível para regex (você precisará armazenar em cache o objeto regex, por exemplo). Mas o cerne do problema é que a "qualidade" dos dados será muito importante. Talvez com seqüências longas o regex supere as outras opções. Será uma referência divertida para executar ... :-)
Loudenvier

11
Como default (string []) == uma lista de todos os caracteres de espaço em branco? Eu vejo isso funcionando, mas não estou entendendo como?
Jake de Drew

5
@kernowcode Você quer dizer a ambiguidade entre as 2 sobrecargas com string[]e char[]? você apenas tem que especificar qual deles você deseja, por exemplo: string.Join("", str.Split((string[])null, StringSplitOptions.RemoveEmptyEntries));. Na verdade, é o que a sua chamada defaultfaz nesse caso, pois também retorna null: ajuda o compilador a decidir qual sobrecarga escolher. Daí o meu comentário porque a declaração no seu comentário "Split precisa de uma matriz válida e nula não funciona ..." é falsa. Não é grande coisa, só pensei em mencionar uma vez que Jake Drew perguntou como isso funcionava. +1 para a sua resposta
Frank J

6
Arrefecer ideia ... mas eu gostaria de fazê-lo da seguinte forma:string.Concat("H \ne llo Wor ld".Split())
michaelkrisper

3
A solução michaelkrisper é muito legível. Fiz um teste e o 'split / join' (162 milissegundos) teve um desempenho melhor que o 'split / concat' (180 milissegundos) para 10.000 iterações da mesma string.
Kernowcode 5/09/16

45

Com base na resposta de Henks , criei alguns métodos de teste com sua resposta e alguns métodos adicionados e mais otimizados. Descobri que os resultados diferem com base no tamanho da string de entrada. Portanto, testei com dois conjuntos de resultados. No método mais rápido, a fonte vinculada tem uma maneira ainda mais rápida. Mas, como é caracterizado como inseguro, deixei isso de fora.

Resultados de cadeia de entrada longa:

  1. InPlaceCharArray: 2021 ms ( resposta do Sunsetquest ) - ( fonte original )
  2. Divisão de sequência e junção: 4277ms ( resposta do Kernowcode )
  3. Leitor de cordas: 6082 ms
  4. LINQ usando nativo char.IsWhitespace: 7357 ms
  5. LINQ: 7746 ms ( resposta de Henk )
  6. ForLoop: 32320 ms
  7. RegexCompiled: 37157 ms
  8. Regex: 42940 ms

Resultados curtos da string de entrada:

  1. InPlaceCharArray: 108 ms ( resposta do Sunsetquest ) - ( fonte original )
  2. Divisão de sequência e junção: 294 ms ( resposta do Kernowcode )
  3. Leitor de cordas: 327 ms
  4. ForLoop: 343 ms
  5. LINQ usando nativo char.IsWhitespace: 624 ms
  6. LINQ: 645ms ( resposta de Henk )
  7. RegexCompiled: 1671 ms
  8. Regex: 2599 ms

Código :

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);
    }
}

Testes :

[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);
    }
}

Edit : Testado um belo liner do Kernowcode.


24

Apenas uma alternativa, porque parece bastante agradável :) - NOTA: A resposta de Henks é a mais rápida delas.

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

Testando 1.000.000 de loops em "This is a simple Test"

Este método = 1,74 segundos
Regex = 2,58 segundos
new String(Henks) = 0,82


11
Por que isso foi prejudicado? É perfeitamente aceitável, atende aos requisitos, funciona mais rápido que a opção RegEx e é muito legível?
BlueChippy

4
porque pode ser escrito muito mais curto: nova string (input.Where (c =>! Char.IsWhiteSpace (c)). ToArray ());
Bas Smit

7
Pode ser verdade - mas a resposta ainda permanece, é legível, mais rápida que o regex e produz o resultado desejado. Muitas das outras respostas estão APÓS esta ... portanto, um voto negativo não faz sentido.
BlueChippy

2
Existe uma unidade para "0,82"? Ou é uma medida relativa (82%)? Você pode editar sua resposta para torná-la mais clara?
Peter Mortensen

20

Encontrei um ótimo artigo sobre isso no CodeProject de Felipe Machado (com a ajuda de Richard Robertson )

Ele testou dez métodos diferentes. Esta é a versão insegura mais rápida ...

public static unsafe string TrimAllWithStringInplace(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;
            }

        return new string(pfixed, 0, (int)(dst - pfixed));
    }
}

E a versão mais rápida e segura ...

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);
}

Existem também alguns bons benchmarks independentes no Stack Overflow de Stian Standahl que também mostram como a função de Felipe é cerca de 300% mais rápida que a próxima função mais rápida.


Eu tentei traduzir isso para C ++, mas estou um pouco preso. Alguma idéia de por que minha porta pode estar falhando? stackoverflow.com/questions/42135922/…
Jon Cage

2
Eu não posso resistir. Veja a seção de comentários do artigo a que você se refere. Você me encontrará como "Basketcase Software". Ele trabalhou nisso por um tempo. Eu tinha esquecido completamente disso quando esse problema voltou à tona. Obrigado por boas lembranças. :)
Richard Robertson

11
E se você quiser remover apenas os WS extras? E esse mod stackoverflow.com/questions/17770202/… ?
Tom

O mais rápido é um pouco mais lento ;-) Seqüência de caracteres como o contêiner é melhor aqui (no aplicativo 4:15 a 3:55 => 8,5% menos, mas quando deixada a corda é 3:30 => 21,4% menos e o profiller mostra cerca de 50% gastos em este método). Portanto, na cadeia real ao vivo deve ser cerca de 40% mais rápida em comparação à conversão de matriz (lenta) usada aqui.
Tom

15

Se você precisar de um desempenho excelente, evite o LINQ e as expressões regulares nesse caso. Fiz alguns testes de desempenho e parece que, se você deseja remover o espaço em branco do início e do fim da string, string.Trim () é sua função final.

Se você precisar remover todos os espaços em branco de uma sequência, o método a seguir funcionará mais rapidamente do que foi postado aqui:

    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);
    }

Eu ficaria curioso para saber os detalhes dos seus benchmarks - não que eu seja cético, mas estou curioso sobre as despesas gerais envolvidas com o Linq. Quão ruim foi?
Mark Meuer

Não refiz todos os testes, mas me lembro disso: tudo o que envolvia o Linq era muito mais lento do que qualquer coisa sem ele. Todo o uso inteligente de funções e construtores de string / char não fez diferença percentual se o Linq foi usado.
JHM

11

Regex é um exagero; basta usar extensão na string (obrigado Henk). Isso é trivial e deveria ter sido parte da estrutura. De qualquer forma, aqui está a minha implementação:

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

este é basicamente uma resposta desnecessária (regex é um exagero, mas é uma solução mais rápida do que dado um - e já é aceito?)
W1ll1amvl

Como você pode usar os métodos de extensão Linq em uma string? Não consigo descobrir qual uso estou faltando outros que não #System.Linq
GGirard

Parece ok como este não está disponível em PCL, IEnumerable <char> é condicional na implementação da Microsoft da corda ... E eu estou usando Profile259 que não suporta este :)
GGirard

4

Aqui está uma alternativa linear simples à solução RegEx. Não tenho certeza do que é mais rápido; você teria que compará-lo.

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();
}

3

Eu precisava substituir o espaço em branco em uma string por espaços, mas não espaços duplicados. por exemplo, eu precisava converter algo como o seguinte:

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

para

"a b c d e"

Eu usei o seguinte método

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();
}

2

Presumo que sua resposta XML seja assim:

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

A melhor maneira de processar XML é usar um analisador XML, como LINQ to XML :

var doc = XDocument.Parse(xml);

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

Depois de verificar se uma tag <name> específica tem o valor adequado, eu terminei. A análise do documento não teria alguma sobrecarga?
Corey Ogburn

4
Claro, tem alguma sobrecarga. Mas tem o benefício de estar correto. Uma solução baseada, por exemplo, em regex, é muito mais difícil de acertar. Se você determinar que uma solução LINQ to XML é muito lenta, sempre poderá substituí-la por algo mais rápido. Mas você deve evitar procurar a implementação mais eficiente antes de saber que a correta é muito lenta.
dtb

Isso estará sendo executado nos servidores de back-end do meu empregador. Leve é ​​o que estou procurando. Não quero algo que "simplesmente funcione", mas que seja ideal.
Corey Ogburn

4
LINQ to XML é uma das formas mais leves para corretamente o trabalho com XML em .NET
dtb

1

Aqui está mais uma variante:

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

Como na maioria das outras soluções, não realizei testes exaustivos de benchmark, mas isso funciona bem o suficiente para meus propósitos.


1

Podemos usar:

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

Isso é quase exatamente o mesmo que a resposta de Henk acima. A única diferença é que você verifica null.
precisa

Sim, verifique se o nulo é importante
Tarik BENARAB

11
Talvez isso devesse ter sido apenas um comentário sobre sua resposta. Estou feliz que você tenha trazido isso à tona. Eu não sabia que métodos de extensão poderiam ser chamados em objetos nulos.
precisa

0

Eu encontrei resultados diferentes para ser verdade. Estou tentando substituir todo o espaço em branco por um único espaço e o regex era extremamente lento.

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

O que funcionou da melhor maneira para mim (em C ++ cli) foi:

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 );
}

Tentei a rotina acima primeiro substituindo cada caractere separadamente, mas tive que mudar para fazer substrings para as seções não espaciais. Ao aplicar a uma cadeia de 1.200.000 caracteres:

  • a rotina acima faz isso em 25 segundos
  • a rotina acima + substituição de caracteres separada em 95 segundos
  • a regex foi abortada após 15 minutos.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.