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

381

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

Пример:

1 2 3  4    5

:

1 2 3 4 5
  • 1
    конечный автомат может легко это сделать, но это, вероятно, излишне, если вам нужно только удалить пробелы
  • 0
    Я добавил тест на различные способы сделать это в дублирующем вопросе stackoverflow.com/a/37592018/582061 . Regex был не самым быстрым способом сделать это.
Теги:
string

20 ответов

380
Лучший ответ
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);     
tempo = regex.Replace(tempo, " ");
  • 2
    У меня есть скопировать и вставить это, и это работает. Я действительно не люблю REgex, но на этот раз он спасает мне жизнь.
  • 0
    Это хорошее решение, но если вы не заключите его в метод, большинство программистов не будут знать, что он делает.
Показать ещё 13 комментариев
548

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

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

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

  • 34
    Небольшая модификация: Regex.Replace (source, @ "(\ s) \ s +", "$ 1"); Это вернет первый найденный пробельный тип. Так что, если у вас есть 5 вкладок, он вернет вкладку. Incase кто-то предпочитает это.
  • 0
    @radistao Ваша ссылка для замены строки Javascript, а не для C #.
Показать ещё 4 комментария
36

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

myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);
  • 3
    RegexOptions.Multiline изменяет значение ^ и $, чтобы они соответствовали началу и концу каждой строки ($ = \ n), а не всей многострочной строке. Поскольку \ s эквивалентно [\ f \ n \ r \ t \ v], новые строки следует заменять, даже если опция Multiline отключена.
  • 1
    Ответ Мэтта уже охватил это. Я «верю», что 30 человек просто с завязанными глазами проголосовали за этот ответ :)
36
string xyz = "1   2   3   4   5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));
  • 2
    Regex тоже работает.
  • 3
    Это более читабельно, чем регулярное выражение, я предпочитаю это больше, потому что мне не нужно изучать какой-то другой синтаксис
Показать ещё 4 комментария
21

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

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

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

while(str.Contains("  ")) str = str.Replace("  ", " ");
  • 21
    Это будет гораздо менее эффективно, чем регулярное выражение "{2,}", если строка содержит последовательности из 3 или более пробелов.
  • 2
    @JanGoyvaerts: даже с 10 пробелами регулярное выражение было медленнее, когда я сделал быстрый и грязный тест. При этом требуется всего одна гигантская подстрока, полная пробелов, чтобы полностью убить производительность цикла while. Справедливости ради, я использовал я использовал RegexOptions.Compiled, а не более медленный Regex.Replace.
Показать ещё 1 комментарий
17

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."
14
myString = Regex.Replace(myString, " {2,}", " ");
8

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

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

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

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

Для тех, кому не нравится 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, это должно быть еще быстрее.

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

  • 1
    Это лучший ответ для производительности
5

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

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

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

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

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

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

no Regex, no 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
    Предостережение: использование разделения, хотя и очень простое для понимания, может оказать неожиданно негативное влияние на производительность. Так как может быть создано много строк, вам придется следить за использованием памяти в случае, если вы обрабатываете большие строки этим методом.
4

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

Вы можете сделать это с помощью 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 (" ");
2

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

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

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

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

Конструкция "(? m:" включает параметр "многострочный". Обычно мне нравится включать любые параметры, которые я могу в самом шаблоне, поэтому он более автономный.

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.
  • 0
    да, но вы бы заменили только два пробела одним. Это не поможет X количество пробелов
  • 0
    Тот цикл While позаботится обо всех этих двойных пробелах, которые будут удалены.
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++;
    }
    return sb.ToString();
}

используйте его следующим образом:

string test = removeNestedWhitespaces("1 2 3  4    5".toCharArray());
  • 0
    Это удалит завершающие пробелы
  • 0
    извините за ошибку, я исправил код, теперь он работает как ожидаемая проверенная строка: "1 2 3 4 9" строка результата: "1 2 3 4 9"
1

Я только что написал новый 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 (" ");
  • 1
    зачем создавать метод расширения? почему бы просто не использовать string.Join ()?
0

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

}
0

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

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

ОК для использования на коротких строках, но будет плохо работать на длинных строках с большим количеством пробелов.

0

Старый skool:

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 " ) );
  • 1
    Предполагается, что текст еще не содержит (char)22

Ещё вопросы

Сообщество Overcoder
Наверх
Меню