¿Cómo reemplazo múltiples espacios con un solo espacio en C #?

440

¿Cómo puedo reemplazar múltiples espacios en una cadena con solo un espacio en C #?

Ejemplo:

1 2 3  4    5

sería:

1 2 3 4 5
Pokus
fuente
1
una máquina de estados puede hacerlo fácilmente, pero probablemente sea excesivo si solo lo necesita para eliminar espacios
Adrian
He agregado un punto de referencia sobre las diferentes formas de hacer esto en una pregunta duplicada stackoverflow.com/a/37592018/582061 . Regex no era la forma más rápida de hacer esto.
Stian Standahl

Respuestas:

469
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");
Patrick Desjardins
fuente
2
Tengo copiar y pegar eso y funciona. Realmente no me gusta REgex pero esta vez me salva la vida.
Pokus
99
@Craig un comentario sería suficiente, en mi opinión. // Este bloque reemplaza múltiples espacios con uno ... :)
paulwhit
66
Realmente, RegEx es demasiado para esto.
Joel Coehoorn
11
@ Joel: No puedo estar de acuerdo. De hecho, estoy seguro de que esta forma es más eficiente que la suya para cadenas lo suficientemente grandes y se puede hacer en una sola línea. ¿Dónde está la exageración?
Konrad Rudolph el
24
¡El código de @Oscar Joel no es un simple bucle a través de todos los personajes! Es un bucle anidado oculto que tiene un peor caso cuadrático. Esta expresión regular, por el contrario, es lineal, solo acumula una sola cadena (= costos de asignación drásticamente reducidos en comparación con el código de Joel) y, además, el motor puede optimizar al máximo (para ser sincero, dudo que la expresión regular .NET sea lo suficientemente inteligente como para esto, pero en teoría esta expresión regular se puede implementar de manera tan económica que ya ni siquiera es graciosa; solo necesita un DFA con tres estados, una transición cada uno y sin información adicional).
Konrad Rudolph el
624

Me gusta usar:

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

Ya que capturará ejecuciones de cualquier tipo de espacio en blanco (por ejemplo, pestañas, líneas nuevas, etc.) y las reemplazará con un solo espacio.

Mate
fuente
43
Ligera modificación: Regex.Replace (fuente, @ "(\ s) \ s +", "$ 1"); Esto devolverá el primer tipo de espacio en blanco encontrado. Entonces, si tiene 5 pestañas, devolverá una pestaña. En caso de que alguien prefiera esto.
FB ten Kate
@radistao Su enlace es para reemplazar la cadena Javascript, no para C #.
Shiva
1
@Shiva, / \ s \ s + / es una declaración de expresión regular POSIX estándar y se puede convertir / usar en cualquier idioma usando su propia sintaxis
radistao
44
En el espíritu de la solución de @ FBtenKate: Regex.Replace (fuente, @ "(\ s) \ 1+", "$ 1"); reemplazará varios caracteres consecutivos idénticos por uno solo.
François Beaune
1
para eliminar espacios en blanco iniciales y finales, debe usar la función Trim () con esto, como var myString = Regex.Replace (myString, @ "\ s +", "") .Trim ();
Harish Nayak
50
string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));
tvanfosson
fuente
66
Esto es más legible que regex, prefiero más porque no necesito aprender otra sintaxis
Michael Bahig
99
Me gusta porque no necesita Regex
AleX_
3
Esto sería ineficiente para cadenas grandes.
DarcyThomas
3
Esto también elimina los espacios iniciales y finales.
Matzi
1
Prefiero esta respuesta también. Mi antiguo mentor solía decir "cada vez que tienes un problema crees que necesitas que Regex lo resuelva, bueno ... ahora tienes DOS problemas" <wink>
William Madonna Jr.
38

Creo que la respuesta de Matt es la mejor, pero no creo que sea correcta. Si desea reemplazar las nuevas líneas, debe usar:

myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);
Brenda Bell
fuente
44
RegexOptions.Multiline cambia el significado de ^ y $ para que coincidan con el principio y el final de cada línea ($ = \ n), en lugar de la cadena completa de varias líneas. Como \ s es equivalente a [\ f \ n \ r \ t \ v], las nuevas líneas deben reemplazarse incluso si la opción Multilínea está desactivada.
SushiGuy
1
La respuesta de Matt ya ha cubierto esto. 'Creo' que 30 personas con los ojos vendados votaron por esta respuesta :)
123iamking
26

Otro enfoque que usa LINQ:

 var list = str.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));
 str = string.Join(" ", list);
cuongle
fuente
23

Es mucho más simple que todo eso:

while(str.Contains("  ")) str = str.Replace("  ", " ");
Joel Coehoorn
fuente
23
Esto será mucho menos eficiente que la expresión regular "{2,}" si la cadena contiene secuencias de 3 o más espacios.
Jan Goyvaerts
2
@ JanGoyvaerts: Incluso con 10 espacios, la expresión regular fue más lenta cuando hice una prueba rápida y sucia. Dicho esto, solo se necesita una subcadena gigante llena de espacios para eliminar por completo el rendimiento del ciclo while. Para ser justos, usé RegexOptions.Compiled, en lugar del Regex.Replace más lento.
Brian
55
RegexOptions.Compiled agrega una gran cantidad de gastos generales al compilar la expresión regular en IL. No lo use a menos que su aplicación use la expresión regular con suficiente frecuencia o en cadenas lo suficientemente grandes como para que la mayor velocidad de coincidencia compense la menor velocidad de compilación.
Jan Goyvaerts
Este es un ejemplo de código extremadamente ineficiente. Jajaja
pcbabu
1
@pcbabu No es tan malo como parece en muchos casos. El Replace()método manejará todas las ocurrencias de dos espacios en una cadena dada, por lo que no estamos haciendo un bucle (y reasignando una cadena completa) para cada instancia de espacios emparejados en la cadena. Una nueva asignación se encargará de todos ellos. Solo volvemos a ejecutar el ciclo cuando había 3 o más espacios juntos, lo que probablemente sea una ocurrencia más rara para muchas fuentes de entrada. Si puede mostrar que se convierte en un problema para sus datos, vaya a escribir la máquina de estado para insertar carácter por carácter en un nuevo generador de cadenas.
Joel Coehoorn
21

Regex puede ser bastante lento incluso con tareas simples. Esto crea un método de extensión que puede usarse fuera de cualquier string.

    public static class StringExtension
    {
        public static String ReduceWhitespace(this String value)
        {
            var newString = new StringBuilder();
            bool previousIsWhitespace = false;
            for (int i = 0; i < value.Length; i++)
            {
                if (Char.IsWhiteSpace(value[i]))
                {
                    if (previousIsWhitespace)
                    {
                        continue;
                    }

                    previousIsWhitespace = true;
                }
                else
                {
                    previousIsWhitespace = false;
                }

                newString.Append(value[i]);
            }

            return newString.ToString();
        }
    }

Sería utilizado como tal:

string testValue = "This contains     too          much  whitespace."
testValue = testValue.ReduceWhitespace();
// testValue = "This contains too much whitespace."
ScubaSteve
fuente
15
myString = Regex.Replace(myString, " {2,}", " ");
Jan Goyvaerts
fuente
11

Para aquellos a quienes no les gusta Regex, aquí hay un método que utiliza StringBuilder:

    public static string FilterWhiteSpaces(string input)
    {
        if (input == null)
            return string.Empty;

        StringBuilder stringBuilder = new StringBuilder(input.Length);
        for (int i = 0; i < input.Length; i++)
        {
            char c = input[i];
            if (i == 0 || c != ' ' || (c == ' ' && input[i - 1] != ' '))
                stringBuilder.Append(c);
        }
        return stringBuilder.ToString();
    }

En mis pruebas, este método fue 16 veces más rápido en promedio con un conjunto muy grande de cadenas de tamaño pequeño a mediano, en comparación con un Regex compilado estático. En comparación con un Regex no compilado o no estático, esto debería ser aún más rápido.

Tenga en cuenta que no elimina los espacios iniciales o finales, solo ocurre múltiples veces .

Nolonar
fuente
Si desea verificar si el carácter es un espacio en blanco, y no solo un espacio, vea mi respuesta a continuación .
Coseche el
8

¡Simplemente puede hacer esto en una solución de línea!

string s = "welcome to  london";
s.Replace(" ", "()").Replace(")(", "").Replace("()", " ");

Puede elegir otros corchetes (o incluso otros caracteres) si lo desea.

ravish.hacker
fuente
1
Debe asegurarse de que su cadena no tenga "()" o ") (" en ella. O se "wel()come to london)("convierte "wel come to london". Puede intentar usar muchos corchetes. Por lo tanto, use en ((((()))))lugar de ()y en )))))(((((lugar de )(. Todavía funcionará. Aún así, si la cadena contiene ((((()))))o )))))(((((, esto fallará.
nmit026
7

Esta es una versión más corta, que solo debe usarse si solo lo hace una vez, ya que crea una nueva instancia de la Regexclase cada vez que se llama.

temp = new Regex(" {2,}").Replace(temp, " "); 

Si no está demasiado familiarizado con las expresiones regulares, aquí hay una breve explicación:

Esto {2,}hace que la expresión regular busque el carácter que le precede, y encuentra subcadenas entre 2 e ilimitadas veces.
El .Replace(temp, " ")reemplaza todas las coincidencias en la cadena temporal con un espacio.

Si desea usar esto varias veces, aquí hay una mejor opción, ya que crea la IL de expresión regular en tiempo de compilación:

Regex singleSpacify = new Regex(" {2,}", RegexOptions.Compiled);
temp = singleSpacify.Replace(temp, " ");
alguien
fuente
7

no Regex, no Linq ... elimina los espacios iniciales y finales, así como reduce cualquier segmento de espacio múltiple incrustado a un espacio

string myString = "   0 1 2  3   4               5  ";
myString = string.Join(" ", myString.Split(new char[] { ' ' }, 
StringSplitOptions.RemoveEmptyEntries));

resultado: "0 1 2 3 4 5"

Stephen du Buis
fuente
1
Una advertencia: el uso de la división, si bien es muy sencillo de entender, puede tener un impacto sorprendentemente negativo en el rendimiento. Como se pueden crear muchas cadenas, tendrá que vigilar el uso de su memoria en caso de que maneje cadenas grandes con este método.
Pac0
5

Consolidando otras respuestas, según Joel, y con suerte mejorando ligeramente a medida que avanzo:

Puedes hacer esto con Regex.Replace():

string s = Regex.Replace (
    "   1  2    4 5", 
    @"[ ]{2,}", 
    " "
    );

O con String.Split():

static class StringExtensions
{
    public static string Join(this IList<string> value, string separator)
    {
        return string.Join(separator, value.ToArray());
    }
}

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");
Jay Bazuzi
fuente
3

Acabo de escribir una nueva Joinque me gusta, así que pensé en volver a responder, con ella:

public static string Join<T>(this IEnumerable<T> source, string separator)
{
    return string.Join(separator, source.Select(e => e.ToString()).ToArray());
}

Una de las cosas interesantes de esto es que funciona con colecciones que no son cadenas, al llamar a ToString () en los elementos. El uso sigue siendo el mismo:

//...

string s = "     1  2    4 5".Split (
    " ".ToCharArray(), 
    StringSplitOptions.RemoveEmptyEntries
    ).Join (" ");
Jay Bazuzi
fuente
2
¿Por qué crear un método de extensión? ¿Por qué no usar string.Join ()?
Eric Schoonover el
3
      // Mysample string
            string str ="hi you           are          a demo";

            //Split the words based on white sapce
            var demo= str .Split(' ').Where(s => !string.IsNullOrWhiteSpace(s));

            //Join the values back and add a single space in between
                    str = string.Join(" ", demo);

//output: string str ="hi you are a demo";
JIYAUL MUSTAPHA
fuente
2

Sé que esto es bastante viejo, pero me encontré con esto al intentar lograr casi lo mismo. Encontré esta solución en RegEx Buddy. Este patrón reemplazará todos los espacios dobles con espacios individuales y también recortará los espacios iniciales y finales.

pattern: (?m:^ +| +$|( ){2,})
replacement: $1

Es un poco difícil de leer ya que estamos tratando con un espacio vacío, así que aquí está nuevamente con los "espacios" reemplazados por un "_".

pattern: (?m:^_+|_+$|(_){2,})  <-- don't use this, just for illustration.

La construcción "(? M:" habilita la opción "multilínea". En general, me gusta incluir todas las opciones que pueda dentro del patrón para que sea más autónomo.

Paul Easter
fuente
2

Muchas respuestas están proporcionando el resultado correcto, pero para aquellos que buscan las mejores actuaciones, mejoré la respuesta de Nolanar (que fue la mejor respuesta para el rendimiento) en aproximadamente un 10%.

public static string MergeSpaces(this string str)
{

    if (str == null)
    {
        return null;
    }
    else
    {
        StringBuilder stringBuilder = new StringBuilder(str.Length);

        int i = 0;
        foreach (char c in str)
        {
            if (c != ' ' || i == 0 || str[i - 1] != ' ')
                stringBuilder.Append(c);
            i++;
        }
        return stringBuilder.ToString();
    }

}
The_Black_Smurf
fuente
1

Puedo eliminar espacios en blanco con esto

while word.contains("  ")  //double space
   word = word.Replace("  "," "); //replace double space by single space.
word = word.trim(); //to remove single whitespces from start & end.
Estudiante1947
fuente
sí, pero solo reemplazarías dos espacios en blanco por uno. Esto no ayudaría a X número de espacios
MGot90
1
Ese bucle While se encargará de eliminar todos los espacios dobles.
Learner1947
1

Usa el patrón regex

    [ ]+    #only space

   var text = Regex.Replace(inputString, @"[ ]+", " ");
M.Hassan
fuente
1

prueba este método

private string removeNestedWhitespaces(char[] st)
{
    StringBuilder sb = new StringBuilder();
    int indx = 0, length = st.Length;
    while (indx < length)
    {
        sb.Append(st[indx]);
        indx++;
        while (indx < length && st[indx] == ' ')
            indx++;
        if(sb.Length > 1  && sb[0] != ' ')
            sb.Append(' ');
    }
    return sb.ToString();
}

úsalo así:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());
Ahmed Aljaff
fuente
Esto eliminará los espacios finales
The_Black_Smurf
lo siento por el error, i fijo el código, ahora es el trabajo como se esperaba cadena de prueba: "1 2 3 4 9" cadena de resultado: "1 2 3 4 9"
Ahmed Aljaff
1

Aquí hay una ligera modificación en la respuesta original de Nolonar .

Verificando si el personaje no es solo un espacio, sino cualquier espacio en blanco, use esto:

Reemplazará cualquier carácter de espacio en blanco múltiple con un solo espacio.

public static string FilterWhiteSpaces(string input)
{
    if (input == null)
        return string.Empty;

    var stringBuilder = new StringBuilder(input.Length);
    for (int i = 0; i < input.Length; i++)
    {
        char c = input[i];
        if (i == 0 || !char.IsWhiteSpace(c) || (char.IsWhiteSpace(c) && 
            !char.IsWhiteSpace(strValue[i - 1])))
            stringBuilder.Append(c);
    }
    return stringBuilder.ToString();
}
Recoger
fuente
0

Vieja escuela:

string oldText = "   1 2  3   4    5     ";
string newText = oldText
                    .Replace("  ", " " + (char)22 )
                    .Replace( (char)22 + " ", "" )
                    .Replace( (char)22 + "", "" );

Assert.That( newText, Is.EqualTo( " 1 2 3 4 5 " ) );
un día cuando
fuente
0

Sin usar expresiones regulares:

while (myString.IndexOf("  ", StringComparison.CurrentCulture) != -1)
{
    myString = myString.Replace("  ", " ");
}

Está bien usarlo en cadenas cortas, pero funcionará mal en cadenas largas con muchos espacios.

Tom Gullen
fuente
0

Mezcla de StringBuilder y Enumerable.Aggregate () como método de extensión para cadenas:

using System;
using System.Linq;
using System.Text;

public static class StringExtension
{
    public static string StripSpaces(this string s)
    {
        return s.Aggregate(new StringBuilder(), (acc, c) =>
        {
            if (c != ' ' || acc.Length > 0 && acc[acc.Length-1] != ' ')
                acc.Append(c);

            return acc;
        }).ToString();
    }

    public static void Main()
    {
        Console.WriteLine("\"" + StringExtension.StripSpaces("1   Hello       World  2   ") + "\"");
    }
}

Entrada:

"1   Hello       World  2   "

Salida:

"1 Hello World 2 "
Patrick Artner
fuente