Как заменить несколько пробелов одним пробелом в C #?


440

Как я могу заменить несколько пробелов в строке только одним пробелом в C #?

Пример:

1 2 3  4    5

было бы:

1 2 3 4 5

1
конечный автомат может легко это сделать, но он, вероятно, излишним, если вам нужно только удалить пробелы
Адриан

Я добавил тест на различные способы сделать это в дублирующем вопросе stackoverflow.com/a/37592018/582061 . Regex был не самым быстрым способом сделать это.
Stian Standahl

Ответы:


470
string sentence = "This is a sentence with multiple    spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
sentence = regex.Replace(sentence, " ");

3
У меня есть скопировать и вставить это, и это работает. Я действительно не люблю REgex, но на этот раз он спасает мне жизнь.
Покус

9
@ Достаточно написать комментарий, ИМО. // Этот блок заменяет несколько пробелов одним ... :)
paulwhit 15.10.08

6
На самом деле, RegEx излишне для этого.
Джоэл Коухорн

11
@Joel: не могу согласиться. Я действительно уверен, что этот способ более эффективен, чем ваш, для достаточно больших строк и может быть выполнен в одну строку. Где перегиб?
Конрад Рудольф

24
@ Код Оскара Джоэла не простой цикл для всех символов! Это скрытый вложенный цикл с квадратичным наихудшим случаем. Это регулярное выражение, напротив, является линейным, формирует только одну строку (= радикально уменьшенные затраты на выделение ресурсов по сравнению с кодом Джоэла) и, кроме того, движок может чертовски оптимизировать его (честно говоря, я сомневаюсь, что регулярное выражение .NET достаточно умный для этого, но теоретически это регулярное выражение может быть реализовано настолько дешево, что это даже не смешно: ему нужен только DFA с тремя состояниями, по одному переходу в каждом, и без дополнительной информации).
Конрад Рудольф

624

Мне нравится использовать:

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

Поскольку он будет перехватывать любые пробелы (например, табуляции, новые строки и т. Д.) И заменять их одним пробелом.


43
Небольшая модификация: Regex.Replace (source, @ "(\ s) \ s +", "$ 1"); Это вернет первый найденный пробельный тип. Так что, если у вас есть 5 вкладок, он вернет вкладку. Incase кто-то предпочитает это.
FB ten Kate

@radistao Ваша ссылка для замены строки Javascript, а не для C #.
Шива

1
@Shiva, / \ s \ s + / является стандартным оператором регулярных выражений POSIX и может быть преобразован / использован на любом языке с использованием собственного синтаксиса
radistao

4
В духе решения @ FBtenKate: Regex.Replace (source, @ "(\ s) \ 1+", "$ 1"); заменит несколько одинаковых последовательных символов одним.
Франсуа Бон

1
чтобы удалить начальные и конечные пробелы, вы должны использовать функцию Trim () с этим, например, var myString = Regex.Replace (myString, @ "\ s +", "") .Trim ();
Хариш Наяк

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

6
Это более читабельно по сравнению с регулярными выражениями, я предпочитаю это больше, потому что мне не нужно изучать какой-то другой синтаксис
Майкл Бахиг

9
Мне это нравится, потому что ему не нужно
регулярное выражение

3
Это было бы неэффективно для больших строк.
DarcyThomas

3
Это также удаляет начальные и конечные пробелы.
Matzi

1
Я тоже предпочитаю этот ответ. Мой старый наставник обычно говорил: «Каждый раз, когда у тебя возникает проблема, ты думаешь, что Regex нужно решать, ну ... теперь у тебя ДВА проблемы» <wink>
Уильям Мадонна младший

38

Я думаю, что ответ Мэтта самый лучший, но я не верю, что он совершенно прав. Если вы хотите заменить символы новой строки, вы должны использовать:

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

4
RegexOptions.Multiline изменяет значение ^ и $, чтобы они соответствовали началу и концу каждой строки ($ = \ n) вместо всей многострочной строки. Поскольку \ s эквивалентно [\ f \ n \ r \ t \ v], новые строки следует заменять, даже если опция Multiline отключена.
SushiGuy

1
Ответ Мэтта уже охватил это. Я «верю», что 30 человек просто с завязанными глазами проголосовали за этот ответ :)
123iamking

26

Другой подход, который использует LINQ:

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

23

Это намного проще, чем все это:

while(str.Contains("  ")) str = str.Replace("  ", " ");

23
Это будет гораздо менее эффективно, чем регулярное выражение "{2,}", если строка содержит последовательности из 3 или более пробелов.
Ян Гойваертс

2
@JanGoyvaerts: даже с 10 пробелами регулярное выражение было медленнее, когда я сделал быстрый и грязный тест. При этом требуется всего одна гигантская подстрока, полная пробелов, чтобы полностью убить производительность цикла while. Справедливости ради, я использовал я использовал RegexOptions.Compiled, а не более медленный Regex.Replace.
Брайан

5
RegexOptions.Compiled добавляет много накладных расходов при компиляции регулярного выражения в IL. Не используйте его, если ваше приложение не будет использовать регулярное выражение достаточно часто или на достаточно больших строках, чтобы увеличение скорости совпадения компенсировало снижение скорости компиляции.
Ян Гойваертс

Это пример крайне неэффективного кода. ЛОЛ.
pcbabu

1
@pcbabu Это не так плохо, как кажется во многих случаях. Replace()Метод будет обрабатывать все вхождения двух пространств в данной строке, поэтому мы не зацикливание (и повторное выделение целой строки) для каждого экземпляра спаренных пробелов в строке. Одно новое распределение будет обрабатывать все из них. Мы перезапускаем цикл только тогда, когда было 3 или более пробелов вместе, что, вероятно, является более редким явлением для многих входных источников. Если вы можете показать, что это становится проблемой для ваших данных, тогда напишите конечный автомат, чтобы вставить символ за символом в новый построитель строк.
Джоэл Коухорн

21

Regex может быть довольно медленным даже с простыми задачами. Это создает метод расширения, который можно использовать для любого 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();
        }
    }

Это будет использоваться как таковой:

string testValue = "This contains     too          much  whitespace."
testValue = testValue.ReduceWhitespace();
// testValue = "This contains too much whitespace."


11

Для тех, кто не любит Regex, вот метод, который использует 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();
    }

В моих тестах этот метод был в среднем в 16 раз быстрее с очень большим набором строк малого и среднего размера по сравнению со статически скомпилированным Regex. По сравнению с не скомпилированным или нестатичным Regex, это должно быть еще быстрее.

Имейте в виду, что он не удаляет начальные или конечные пробелы, только многократные появления таких.


Если вы хотите проверить, является ли символ пробелом, а не просто пробелом, смотрите мой ответ ниже .
Рип

8

Вы можете просто сделать это в одном решении линии!

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

Вы можете выбрать другие скобки (или даже другие символы), если хотите.


1
Вы должны убедиться, что в вашей строке нет "()" или ") (" внутри. Или "wel()come to london)("становится "wel come to london". Вы можете попробовать использовать много скобок. Поэтому используйте ((((()))))вместо ()и )))))(((((вместо )(. Это все равно будет работать. Тем не менее, если строка содержит ((((()))))или )))))(((((, это не удастся.
nmit026

7

Это более короткая версия, которую следует использовать только в том случае, если вы делаете это только один раз, поскольку она создает новый экземпляр Regexкласса при каждом вызове.

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

Если вы не слишком знакомы с регулярными выражениями, вот краткое объяснение:

Команда {2,}regex ищет предшествующий ему символ и находит подстроки от 2 до неограниченного времени. Заменяет все матчи в строке температуры с пробелом.
.Replace(temp, " ")

Если вы хотите использовать это несколько раз, вот лучший вариант, так как он создает регулярное выражение IL во время компиляции:

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

7

нет Regex, нет Linq ... удаляет начальные и конечные пробелы, а также сокращает любые вложенные сегменты нескольких пробелов в один пробел

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

результат: "0 1 2 3 4 5"


1
Предостережение: использование разделения, хотя и очень простое для понимания, может оказать неожиданно негативное влияние на производительность. Так как может быть создано много строк, вам придется следить за использованием памяти в случае, если вы обрабатываете большие строки этим методом.
Pac0

5

Утешает другие ответы, согласно Джоэлу, и, надеюсь, немного улучшается:

Вы можете сделать это с Regex.Replace():

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

Или с 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 (" ");

3

Я просто написал новый, Joinкоторый мне нравится, поэтому я решил, что я отвечу, с этим:

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

Одна из замечательных особенностей этого - то, что он работает с коллекциями, которые не являются строками, вызывая ToString () для элементов. Использование остается прежним:

//...

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

2
зачем создавать метод расширения? почему бы просто не использовать string.Join ()?
Эрик Шуновер

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";

2

Я знаю, что это довольно старый, но наткнулся на это, пытаясь достичь почти того же. Нашел это решение в RegEx Buddy. Этот шаблон заменит все двойные пробелы одиночными пробелами, а также урежет начальные и конечные пробелы.

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

Его немного сложно прочитать, поскольку мы имеем дело с пустым пространством, поэтому здесь снова с "пробелами", замененными на "_".

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

Конструкция "(? M:" включает опцию "multi-line". Я обычно хотел бы включить все возможные варианты в сам шаблон, чтобы он был более автономным.


2

Многие ответы дают правильный результат, но для тех, кто ищет лучшие результаты, я улучшил ответ Ноланара (который был лучшим ответом для производительности) примерно на 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();
    }

}

1

Я могу удалить пробелы с этим

while word.contains("  ")  //double space
   word = word.Replace("  "," "); //replace double space by single space.
word = word.trim(); //to remove single whitespces from start & end.

да, но вы бы заменили только два пробела одним. Это не поможет X количество пробелов
MGot90

1
Тот цикл While позаботится обо всех этих двойных пробелах, которые будут удалены.
Learner1947

1

Используйте шаблон регулярных выражений

    [ ]+    #only space

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

1

попробуйте этот метод

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

используйте это так:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());

Это удалит завершающие пробелы
The_Black_Smurf

извините за ошибку, я исправил код, теперь он работает, как и ожидалось, проверенная строка: "1 2 3 4 9" строка результата: "1 2 3 4 9"
Ахмед Аляфф

1

Вот небольшая модификация на Nolonar оригинальный ответ .

Проверка, является ли символ не просто пробелом, а пробелом, используйте это:

Он заменит любой символ пробела одним пробелом.

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

0

Старая школа:

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

0

Без использования регулярных выражений:

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

Можно использовать на коротких строках, но плохо работает на длинных строках с большим количеством пробелов.


0

Смесь StringBuilder и Enumerable.Aggregate () в качестве метода расширения для строк:

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   ") + "\"");
    }
}

Входные данные:

"1   Hello       World  2   "

Вывод:

"1 Hello World 2 "
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.