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

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

Пример:

1 2 3  4    5

было бы:

1 2 3 4 5

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

Adrian 06.01.2012 23:20

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

Stian Standahl 03.06.2016 07:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
480
2
314 120
25
Перейти к ответу Данный вопрос помечен как решенный

Ответы 25

Ответ принят как подходящий

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

У меня есть копия и вставка, и это работает. Мне очень не нравится REgex, но на этот раз он спасает мне жизнь.

Pokus 16.10.2008 02:22

Это хорошее решение, но если вы не заключите его в метод, большинство программистов не поймут, что он делает.

Craig 16.10.2008 02:27

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

paulwhit 16.10.2008 03:40

@Pokus, RegEx - это чудесно мощный инструмент для изучения и использования, как только вы пройдете начальную кривую обучения, вы удивитесь, как вы когда-либо жили без него.

Mark 16.10.2008 03:42

Есть небольшая ошибка, должна быть @ "", а не @ "".

DK. 20.10.2008 21:52

На самом деле RegEx для этого - излишество.

Joel Coehoorn 28.10.2008 18:01

Вам не нужны квадратные скобки в регулярном выражении. Просто используйте "{2,}".

Jan Goyvaerts 20.11.2008 10:20

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

Konrad Rudolph 23.11.2008 19:27

Также регулярное выражение гораздо более очевидно, чем повторный поиск и замена IMHO.

lacop 23.11.2008 19:34

Regex может быть скомпилирован, поскольку его можно повторно использовать в его форме.

Andrei Rînea 24.05.2009 12:53

@Konrad Как ты думаешь, это могло бы быть более эффективным? хм ... простого цикла по всем символам текста было бы достаточно, чтобы сделать то же самое без использования RegEx. (Я все равно люблю RegEx: D)

Oscar Mederos 04.03.2011 09:29

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

Konrad Rudolph 04.03.2011 13:17

это сработало для меня. Может быть, вы хотите удалить вкладки. stackoverflow.com/a/26584593/2125322 Если в первом символе есть один пробел, его следует удалить. stackoverflow.com/a/3381992/2125322

matasoy 15.11.2017 00:17

В одной строке: Regex.Replace("multiple spaces", "[ ]{2,}", " ", RegexOptions.None)

datchung 14.05.2020 05:31

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

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

Michael Bahig 24.07.2015 14:56

Мне это нравится, потому что ему не нужно Regex

AleX_ 22.12.2015 21:08

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

DarcyThomas 28.09.2016 07:05

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

Matzi 06.02.2017 00:00

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

William Madonna Jr. 06.04.2018 15:53

Интересно, какая производительность по сравнению с решением с регулярным выражением !!

Umang 07.09.2020 02:55

Он тоже удаляет ввод / вкладку?

Mitulát báti 24.10.2020 16:53

Предпочитал этот. :)

Yaduraj 13.11.2020 17:02

Объединяя другие ответы, за Джоэла, и, надеюсь, немного улучшаюсь по мере того, как я иду:

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

Все намного проще:

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

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

Jan Goyvaerts 20.11.2008 10:22

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

Brian 06.02.2013 19:37

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

Jan Goyvaerts 07.02.2013 08:26

Это пример крайне неэффективного кода. РЖУ НЕ МОГУ.

pcbabu 19.02.2020 22:51

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

Joel Coehoorn 20.02.2020 01:24

Да, теперь я понял. Спасибо за ваше объяснение.

pcbabu 25.02.2020 00:24

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

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

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

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

F.B. ten Kate 14.05.2012 16:56

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

Shiva 28.04.2014 21:58

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

radistao 29.04.2014 10:45

@ F.B.tenKate Хороший вариант. Еще один пример: если у вас есть tab-space-space-tab-newline, он вернет табуляцию.

goodeye 26.01.2015 06:28

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

François Beaune 11.01.2016 20:06

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

Harish Nayak 03.04.2019 05:07

Предложение Франсуа лучше всего, если вы хотите уважать вводимые пользователем данные (например, идеографические пробелы сохраняются, а не заменяются обычными пробелами)

MattWazEre 28.05.2020 04:49

Я только что написал новый 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 (" ");

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

Eric Schoonover 20.11.2008 06:45

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

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

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

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

SushiGuy 06.06.2012 03:27

Ответ Мэтта уже затронул это. Думаю, 30 человек просто с завязанными глазами проголосовали за этот ответ :)

123iamking 08.09.2017 06:50

Другой подход, использующий LINQ:

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

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

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

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

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

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

Reap 14.11.2019 07:22

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

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

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

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

Конструкция «(? M:» включает параметр «многострочный». Обычно мне нравится включать все возможные варианты в сам шаблон, чтобы он был более самодостаточным.

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

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

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

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

nmit026 27.07.2017 01:18

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

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

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

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

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

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

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

Мне нравится идея метода расширения, хотя подпрограмму можно оптимизировать.

henda79 17.12.2020 12:30

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

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 27.02.2018 22:37

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

Ahmed Aljaff 27.08.2018 01:04

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

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 26.07.2016 22:59

Этот цикл while позаботится обо всех этих двойных пробелах, которые нужно удалить.

Learner1947 28.03.2017 19:55

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

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

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

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"

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

Pac0 25.06.2018 18:26

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

}

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

    [ ]+    #only space

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

Сочетание 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 "

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

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

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

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

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

Спасибо, это помогло мне. Небольшая ошибка: strValue, вероятно, должен быть input. Кроме того, IsWhiteSpace включает символы разрыва строки. Вероятно, вы не захотите объединять несколько разрывов строк, хотя бы потому, что это будет вести себя по-разному в зависимости от вашей среды (\r\n против \n). В этом случае проверьте «CharUnicodeInfo.GetUnicodeCategory (c) == UnicodeCategory.SpaceSeparator».

Oliver Schimmer 13.07.2020 18:57

@OliverSchimmer, верно, спасибо за исправление. Добавленная информация о символах Юникода - отличное дополнение. Не стесняйтесь вносить изменения! :)

Reap 13.07.2020 19:31

Разве это не переписывание этого ответа? stackoverflow.com/a/33817748/56621

Alex from Jitbit 15.07.2020 18:30

Я просмотрел предложенные решения и не смог найти того, который обрабатывал бы сочетание символов пробела, приемлемого для моего случая, например:

  • Regex.Replace(input, @"\s+", " ") - съест ваши разрывы строк, если они смешаны с пробелами, например последовательность \n \n будет заменена на
  • Regex.Replace(source, @"(\s)\s+", "$1") - это будет зависеть от первого символа пробела, что означает, что он снова может съесть ваши разрывы строк
  • Regex.Replace(source, @"[ ]{2,}", " ") - он не будет работать правильно, если есть сочетание пробельных символов - например, "\t \t "

Наверное, не идеально, но быстрое решение для меня было:

Regex.Replace(input, @"\s+", 
(match) => match.Value.IndexOf('\n') > -1 ? "\n" : " ", RegexOptions.Multiline)

Идея в том, что разрыв строки побеждает пробелы и табуляции.

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

Другие вопросы по теме