Как я могу заменить несколько пробелов в строке только одним пробелом в C#?
Пример:
1 2 3 4 5
было бы:
1 2 3 4 5
Я добавил тест различных способов сделать это в повторяющемся вопросе stackoverflow.com/a/37592018/582061. Regex был не самым быстрым способом сделать это.





string sentence = "This is a sentence with multiple spaces";
RegexOptions options = RegexOptions.None;
Regex regex = new Regex("[ ]{2,}", options);
sentence = regex.Replace(sentence, " ");
У меня есть копия и вставка, и это работает. Мне очень не нравится REgex, но на этот раз он спасает мне жизнь.
Это хорошее решение, но если вы не заключите его в метод, большинство программистов не поймут, что он делает.
@Craig, комментария будет достаточно, ИМО. // Этот блок заменяет несколько пробелов одним ... :)
@Pokus, RegEx - это чудесно мощный инструмент для изучения и использования, как только вы пройдете начальную кривую обучения, вы удивитесь, как вы когда-либо жили без него.
Есть небольшая ошибка, должна быть @ "", а не @ "".
На самом деле RegEx для этого - излишество.
Вам не нужны квадратные скобки в регулярном выражении. Просто используйте "{2,}".
@ Джоэл: Не могу согласиться. Я действительно уверен, что этот способ более эффективен, чем ваш, для достаточно больших строк и может быть выполнен в одну строку. Где излишество?
Также регулярное выражение гораздо более очевидно, чем повторный поиск и замена IMHO.
Regex может быть скомпилирован, поскольку его можно повторно использовать в его форме.
@Konrad Как ты думаешь, это могло бы быть более эффективным? хм ... простого цикла по всем символам текста было бы достаточно, чтобы сделать то же самое без использования RegEx. (Я все равно люблю RegEx: D)
Код @Oscar Joel - это не простой цикл по всем символам! Это скрытый вложенный цикл с квадратичным наихудшим случаем. Это регулярное выражение, напротив, является линейным, создает только одну строку (= резко сокращенные затраты на выделение ресурсов по сравнению с кодом Джоэла), и, кроме того, движок может оптимизировать его до чертиков (честно говоря, я сомневаюсь, что регулярное выражение .NET является достаточно умен для этого, но теоретически это регулярное выражение может быть реализовано настолько дешево, что это уже даже не смешно; ему нужен только DFA с тремя состояниями, по одному переходу каждое и без дополнительной информации).
это сработало для меня. Может быть, вы хотите удалить вкладки. stackoverflow.com/a/26584593/2125322 Если в первом символе есть один пробел, его следует удалить. stackoverflow.com/a/3381992/2125322
В одной строке: Regex.Replace("multiple spaces", "[ ]{2,}", " ", RegexOptions.None)
string xyz = "1 2 3 4 5";
xyz = string.Join( " ", xyz.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ));
Это более читабельно по сравнению с регулярным выражением, я предпочитаю его больше, потому что мне не нужно изучать какой-либо другой синтаксис
Мне это нравится, потому что ему не нужно Regex
Это было бы неэффективно для больших струн.
Это также удаляет начальные и конечные пробелы.
Я тоже предпочитаю этот ответ. Мой старый наставник говорил: «Каждый раз, когда у вас есть проблема, которую вы думаете, что вам нужно решить Regex, ну ... теперь у вас ДВЕ проблемы» <wink>
Интересно, какая производительность по сравнению с решением с регулярным выражением !!
Он тоже удаляет ввод / вкладку?
Предпочитал этот. :)
Объединяя другие ответы, за Джоэла, и, надеюсь, немного улучшаюсь по мере того, как я иду:
Вы можете сделать это с помощью Regex.Replace():
string s = Regex.Replace (
" 1 2 4 5",
@"[ ]{2,}",
" "
);
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 или более пробелов.
@JanGoyvaerts: Даже с 10 пробелами регулярное выражение было медленнее, когда я сделал быстрый и грязный тест. При этом требуется всего одна гигантская подстрока, полная пробелов, чтобы полностью убить производительность цикла while. Честно говоря, я использовал RegexOptions.Compiled, а не более медленный Regex.Replace.
RegexOptions.Compiled добавляет много накладных расходов на компиляцию регулярного выражения в IL. Не используйте его, если ваше приложение не будет использовать регулярное выражение достаточно часто или на достаточно больших строках, чтобы увеличенная скорость сопоставления компенсировала уменьшенную скорость компиляции.
Это пример крайне неэффективного кода. РЖУ НЕ МОГУ.
@pcbabu Во многих случаях это не так плохо, как кажется. Метод Replace() будет обрабатывать все вхождения двух пробелов в данной строке, поэтому мы не зацикливаемся (и не перераспределяем всю строку) для каждого экземпляра парных пробелов в строке. Все они будут обработаны одним новым распределением. Мы повторно запускаем цикл только тогда, когда вместе было 3 или более пробелов, что, вероятно, будет более редким явлением для многих источников ввода. Если вы можете показать, что это становится проблемой для ваших данных, тогда напишите конечный автомат, чтобы посимвольно передавать новый конструктор строк.
Да, теперь я понял. Спасибо за ваше объяснение.
Мне нравится использовать:
myString = Regex.Replace(myString, @"\s+", " ");
Поскольку он будет ловить пробелы любого вида (например, табуляции, новые строки и т. д.) И заменять их одним пробелом.
Небольшая модификация: Regex.Replace (source, @ "(\ s) \ s +", "$ 1"); Это вернет первый найденный тип пробелов. Итак, если у вас есть 5 вкладок, он вернет вкладку. Если кто-то предпочитает это.
@radistao Ваша ссылка предназначена для замены строки Javascript, а не для C#.
@Shiva, / \ s \ s + / - это стандартный оператор регулярного выражения POSIX, который может быть преобразован / использован на любом языке с использованием собственного синтаксиса.
@ F.B.tenKate Хороший вариант. Еще один пример: если у вас есть tab-space-space-tab-newline, он вернет табуляцию.
В духе решения @F.B.tenKate: Regex.Replace (source, @ "(\ s) \ 1+", "$ 1"); заменит несколько последовательных символов идентичный одним.
чтобы удалить начальные и конечные пробелы, вы должны использовать функцию Trim () с этим, например var myString = Regex.Replace (myString, @ "\ s +", "") .Trim ();
Предложение Франсуа лучше всего, если вы хотите уважать вводимые пользователем данные (например, идеографические пробелы сохраняются, а не заменяются обычными пробелами)
Я только что написал новый 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 ()?
myString = Regex.Replace(myString, " {2,}", " ");
Я думаю, что ответ Мэтта лучший, но я не считаю его правильным. Если вы хотите заменить символы новой строки, вы должны использовать:
myString = Regex.Replace(myString, @"\s+", " ", RegexOptions.Multiline);
RegexOptions.Multiline изменяет значение ^ и $, чтобы они соответствовали началу и концу каждой строки ($ = \ n), а не всей многострочной строке. Поскольку \ s эквивалентен [\ f \ n \ r \ t \ v], новые строки следует заменять, даже если опция «Многострочный» отключена.
Ответ Мэтта уже затронул это. Думаю, 30 человек просто с завязанными глазами проголосовали за этот ответ :)
Другой подход, использующий 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. По сравнению с нескомпилированным или нестатическим регулярным выражением это должно быть еще быстрее.
Имейте в виду, что нет удаляет начальные или конечные пробелы, только несколько таких случаев.
Если вы хотите проверить, является ли символ пробелом, а не просто пробелом, см. мой ответ ниже.
Я знаю, что это довольно давно, но наткнулся на это, пытаясь достичь почти того же самого. Нашел это решение в 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". Вы можете попробовать использовать множество скобок. Поэтому используйте ((((())))) вместо () и )))))((((( вместо )(. Это будет по-прежнему работает .. Тем не менее, если строка содержит ((((())))) или )))))(((((, это не удастся.
Это более короткая версия, которую следует использовать только в том случае, если вы делаете это только один раз, поскольку она создает новый экземпляр класса 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."
Мне нравится идея метода расширения, хотя подпрограмму можно оптимизировать.
попробуйте этот метод
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());
Это удалит конечные пробелы
извините за ошибку, я исправил код, теперь он работает, как ожидалось. Проверенная строка: "1 2 3 4 9" строка результата: "1 2 3 4 9"
Я могу удалить пробелы с помощью этого
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 пробелов
Этот цикл while позаботится обо всех этих двойных пробелах, которые нужно удалить.
Без использования регулярных выражений:
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"
Небольшое предостережение: использование разделения, хотя и очень простое для понимания, может иметь неожиданно негативное влияние на производительность. Поскольку можно создать много строк, вам придется следить за использованием памяти, если вы обрабатываете большие строки с помощью этого метода.
Многие ответы дают правильный результат, но для тех, кто ищет лучшую производительность, я улучшил Ответ ноланара (что было лучшим ответом на производительность) примерно на 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».
@OliverSchimmer, верно, спасибо за исправление. Добавленная информация о символах Юникода - отличное дополнение. Не стесняйтесь вносить изменения! :)
Разве это не переписывание этого ответа? stackoverflow.com/a/33817748/56621
Я просмотрел предложенные решения и не смог найти того, который обрабатывал бы сочетание символов пробела, приемлемого для моего случая, например:
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)
Идея в том, что разрыв строки побеждает пробелы и табуляции.
Это не будет правильно обрабатывать разрывы строк в окнах, но было бы легко настроить работу с этим тоже, не знаю регулярное выражение так хорошо - может быть, можно вписаться в один шаблон.
конечный автомат может легко это сделать, но, вероятно, это будет излишним, если вам нужно только удалить пробелы