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

Предположим, у меня есть строка, такая как:

"Hello how are you doing?" 

Мне нужна функция, которая превращает несколько пробелов в одно пространство.

Поэтому я бы получил:

 "Hello how are you doing?" 

Я знаю, что могу использовать регулярное выражение или позвонить

 string s = "Hello how are you doing?".replace(" "," "); 

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

Есть ли встроенный метод для этого?

 string cleanedString = System.Text.RegularExpressions.Regex.Replace(dirtyString,@"\s+"," "); 

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

Есть разница между «пробелом» и «пробелом». Если вы имеете в виду только пробелы, вы должны использовать регулярное выражение " {2,}" . Если вы имеете в виду любые пробелы, это другое дело. Должны ли все пробелы быть преобразованы в пробелы? Что должно произойти в пространстве в начале и в конце?

Для контрольного показателя ниже я предположил, что вам только небезразличны пробелы, и вы не хотите ничего делать в одиночных пространствах даже в начале и в конце.

Обратите внимание, что правильность почти всегда важнее производительности. Тот факт, что решение Split / Join удаляет любые ведущие / конечные пробелы (даже отдельные пробелы), является неправильным в соответствии с вашими требованиями (что может быть неполным, конечно).

В тесте используется MiniBench .

 using System; using System.Text.RegularExpressions; using MiniBench; internal class Program { public static void Main(string[] args) { int size = int.Parse(args[0]); int gapBetweenExtraSpaces = int.Parse(args[1]); char[] chars = new char[size]; for (int i=0; i < size/2; i += 2) { // Make sure there actually *is* something to do chars[i*2] = (i % gapBetweenExtraSpaces == 1) ? ' ' : 'x'; chars[i*2 + 1] = ' '; } // Just to make sure we don't have a \0 at the end // for odd sizes chars[chars.Length-1] = 'y'; string bigString = new string(chars); // Assume that one form works :) string normalized = NormalizeWithSplitAndJoin(bigString); var suite = new TestSuite("Normalize") .Plus(NormalizeWithSplitAndJoin) .Plus(NormalizeWithRegex) .RunTests(bigString, normalized); suite.Display(ResultColumns.All, suite.FindBest()); } private static readonly Regex MultipleSpaces = new Regex(@" {2,}", RegexOptions.Compiled); static string NormalizeWithRegex(string input) { return MultipleSpaces.Replace(input, " "); } // Guessing as the post doesn't specify what to use private static readonly char[] Whitespace = new char[] { ' ' }; static string NormalizeWithSplitAndJoin(string input) { string[] split = input.Split (Whitespace, StringSplitOptions.RemoveEmptyEntries); return string.Join(" ", split); } } 

Несколько тестовых прогонов:

 c:\Users\Jon\Test>test 1000 50 ============ Normalize ============ NormalizeWithSplitAndJoin 1159091 0:30.258 22.93 NormalizeWithRegex 26378882 0:30.025 1.00 c:\Users\Jon\Test>test 1000 5 ============ Normalize ============ NormalizeWithSplitAndJoin 947540 0:30.013 1.07 NormalizeWithRegex 1003862 0:29.610 1.00 c:\Users\Jon\Test>test 1000 1001 ============ Normalize ============ NormalizeWithSplitAndJoin 1156299 0:29.898 21.99 NormalizeWithRegex 23243802 0:27.335 1.00 

Здесь первое число – это число итераций, второе – время, а третье – масштабированный балл с 1.0 лучшим.

Это показывает, что по крайней мере в некоторых случаях (в том числе и в этом) регулярное выражение может превосходить решение Split / Join, иногда на очень значительный запас.

Однако, если вы переходите на требование «все пробелы», то Split / Join , похоже, победит. Как это часто бывает, дьявол находится в деталях …

Хотя существующие ответы в порядке, я хотел бы указать на один подход, который не работает:

 public static string DontUseThisToCollapseSpaces(string text) { while (text.IndexOf(" ") != -1) { text = text.Replace(" ", " "); } return text; } 

Это может зависеть навсегда. Кто-нибудь должен угадать, почему? (Я только натолкнулся на это, когда его спросили, как вопрос о новостях, несколько лет назад … кто-то на самом деле столкнулся с этим как проблема.)

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

Измените его так:

 string s = System.Text.RegularExpressions.Regex.Replace(s, @"\s{2,}", " "); 

Как уже указывалось, это легко сделать с помощью регулярного выражения. Я просто добавлю, что вы можете добавить .trim () к этому, чтобы избавиться от ведущего / конечного пробела.

Вот решение, с которым я работаю. Без RegEx и String.Split.

 public static string TrimWhiteSpace(this string Value) { StringBuilder sbOut = new StringBuilder(); if (!string.IsNullOrEmpty(Value)) { bool IsWhiteSpace = false; for (int i = 0; i < Value.Length; i++) { if (char.IsWhiteSpace(Value[i])) //Comparion with WhiteSpace { if (!IsWhiteSpace) //Comparison with previous Char { sbOut.Append(Value[i]); IsWhiteSpace = true; } } else { IsWhiteSpace = false; sbOut.Append(Value[i]); } } } return sbOut.ToString(); } 

так что вы можете:

 string cleanedString = dirtyString.TrimWhiteSpace(); 

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

  public static string NormalizeWhiteSpace(string S) { string s = S.Trim(); bool iswhite = false; int iwhite; int sLength = s.Length; StringBuilder sb = new StringBuilder(sLength); foreach(char c in s.ToCharArray()) { if(Char.IsWhiteSpace(c)) { if (iswhite) { //Continuing whitespace ignore it. continue; } else { //New WhiteSpace //Replace whitespace with a single space. sb.Append(" "); //Set iswhite to True and any following whitespace will be ignored iswhite = true; } } else { sb.Append(c.ToString()); //reset iswhitespace to false iswhite = false; } } return sb.ToString(); } 

Используя тестовую программу, которую опубликовал Джон Скит, я попытался понять, могу ли я получить ручную петлю, чтобы работать быстрее.
Я могу каждый раз бить NormalizeWithSplitAndJoin, но только бить NormalizeWithRegex со входами 1000, 5.

 static string NormalizeWithLoop(string input) { StringBuilder output = new StringBuilder(input.Length); char lastChar = '*'; // anything other then space for (int i = 0; i < input.Length; i++) { char thisChar = input[i]; if (!(lastChar == ' ' && thisChar == ' ')) output.Append(thisChar); lastChar = thisChar; } return output.ToString(); } 

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

Так что Regex.Replace () очень быстро и сложно превзойти!

Быстрое дополнительное средство удаления пробелов … Это самый быстрый и основанный на копии на месте Фелипе Мачадо.

 static string InPlaceCharArray(string str) { var len = str.Length; var src = str.ToCharArray(); int dstIdx = 0; bool lastWasWS = false; for (int i = 0; i < len; i++) { var ch = src[i]; if (src[i] == '\u0020') { if (lastWasWS == false) { src[dstIdx++] = ch; lastWasWS = true; } } else { lastWasWS = false; src[dstIdx++] = ch; } } return new string(src, 0, dstIdx); } 

Тесты ...

InPlaceCharArraySpaceOnly by Felipe Machado на CodeProject 2015 и изменен Sunsetquest для удаления нескольких областей. Время: 3,75 Клещи

InPlaceCharArray от Felipe Machado 2015 и немного модифицирован Sunsetquest для удаления нескольких космических объектов. Время 6.50 Клещи (также поддерживаются вкладки)

SplitAndJoinOnSpace от Jon Skeet . Время: 13,25 Клещи

StringBuilder by fubo Время: 13.5 Ticks (также поддерживает вкладки)

Regex с компиляцией Джона Скита . Время: 17

StringBuilder от David S 2013 Время: 30,5 Клещи

Регулярное выражение с не компилируемым Брэндоном Время: 63.25 Клещи

StringBuilder от user214147 Время: 77.125 Ticks

Регулярное с некомпилированным Тимом Хулиханом Время: 147.25 Клещи

Код Benchmark ...

 using System; using System.Text.RegularExpressions; using System.Diagnostics; using System.Threading; using System.Text; static class Program { public static void Main(string[] args) { long seed = ConfigProgramForBenchmarking(); Stopwatch sw = new Stopwatch(); string warmup = "This is a Warm up function for best benchmark results." + seed; string input1 = "Hello World, how are you doing?" + seed; string input2 = "It\twas\t \tso nice to\t\t see you \tin 1950. \t" + seed; string correctOutput1 = "Hello World, how are you doing?" + seed; string correctOutput2 = "It\twas\tso nice to\tsee you in 1950. " + seed; string output1,output2; //warm-up timer function sw.Restart(); sw.Stop(); sw.Restart(); sw.Stop(); long baseVal = sw.ElapsedTicks; // InPlace Replace by Felipe Machado but modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin) output1 = InPlaceCharArraySpaceOnly (warmup); sw.Restart(); output1 = InPlaceCharArraySpaceOnly (input1); output2 = InPlaceCharArraySpaceOnly (input2); sw.Stop(); Console.WriteLine("InPlaceCharArraySpaceOnly : " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); // InPlace Replace by Felipe R. Machado and slightly modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin) output1 = InPlaceCharArray(warmup); sw.Restart(); output1 = InPlaceCharArray(input1); output2 = InPlaceCharArray(input2); sw.Stop(); Console.WriteLine("InPlaceCharArray: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //Regex with non-compile Tim Hoolihan (https://stackoverflow.com/a/1279874/2352507) string cleanedString = output1 = Regex.Replace(warmup, @"\s+", " "); sw.Restart(); output1 = Regex.Replace(input1, @"\s+", " "); output2 = Regex.Replace(input2, @"\s+", " "); sw.Stop(); Console.WriteLine("Regex by Tim Hoolihan: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //Regex with compile by Jon Skeet (https://stackoverflow.com/a/1280227/2352507) output1 = MultipleSpaces.Replace(warmup, " "); sw.Restart(); output1 = MultipleSpaces.Replace(input1, " "); output2 = MultipleSpaces.Replace(input2, " "); sw.Stop(); Console.WriteLine("Regex with compile by Jon Skeet: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //Split And Join by Jon Skeet (https://stackoverflow.com/a/1280227/2352507) output1 = SplitAndJoinOnSpace(warmup); sw.Restart(); output1 = SplitAndJoinOnSpace(input1); output2 = SplitAndJoinOnSpace(input2); sw.Stop(); Console.WriteLine("Split And Join by Jon Skeet: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //Regex by Brandon (https://stackoverflow.com/a/1279878/2352507 output1 = Regex.Replace(warmup, @"\s{2,}", " "); sw.Restart(); output1 = Regex.Replace(input1, @"\s{2,}", " "); output2 = Regex.Replace(input2, @"\s{2,}", " "); sw.Stop(); Console.WriteLine("Regex by Brandon: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //StringBuilder by user214147 (https://stackoverflow.com/a/2156660/2352507 output1 = user214147(warmup); sw.Restart(); output1 = user214147(input1); output2 = user214147(input2); sw.Stop(); Console.WriteLine("StringBuilder by user214147: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //StringBuilder by fubo (https://stackoverflow.com/a/27502353/2352507 output1 = fubo(warmup); sw.Restart(); output1 = fubo(input1); output2 = fubo(input2); sw.Stop(); Console.WriteLine("StringBuilder by fubo: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //StringBuilder by David S 2013 (https://stackoverflow.com/a/16035044/2352507) output1 = SingleSpacedTrim(warmup); sw.Restart(); output1 = SingleSpacedTrim(input1); output2 = SingleSpacedTrim(input2); sw.Stop(); Console.WriteLine("StringBuilder(SingleSpacedTrim) by David S: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); } // InPlace Replace by Felipe Machado and slightly modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin) static string InPlaceCharArray(string str) { var len = str.Length; var src = str.ToCharArray(); int dstIdx = 0; bool lastWasWS = false; for (int i = 0; i < len; i++) { var ch = src[i]; if (src[i] == '\u0020') { if (lastWasWS == false) { src[dstIdx++] = ch; lastWasWS = true; } } else { lastWasWS = false; src[dstIdx++] = ch; } } return new string(src, 0, dstIdx); } // InPlace Replace by Felipe R. Machado but modified by Ryan for multi-space removal (http://www.codeproject.com/Articles/1014073/Fastest-method-to-remove-all-whitespace-from-Strin) static string InPlaceCharArraySpaceOnly (string str) { var len = str.Length; var src = str.ToCharArray(); int dstIdx = 0; bool lastWasWS = false; //Added line for (int i = 0; i < len; i++) { var ch = src[i]; switch (ch) { case '\u0020': //SPACE case '\u00A0': //NO-BREAK SPACE case '\u1680': //OGHAM SPACE MARK case '\u2000': // EN QUAD case '\u2001': //EM QUAD case '\u2002': //EN SPACE case '\u2003': //EM SPACE case '\u2004': //THREE-PER-EM SPACE case '\u2005': //FOUR-PER-EM SPACE case '\u2006': //SIX-PER-EM SPACE case '\u2007': //FIGURE SPACE case '\u2008': //PUNCTUATION SPACE case '\u2009': //THIN SPACE case '\u200A': //HAIR SPACE case '\u202F': //NARROW NO-BREAK SPACE case '\u205F': //MEDIUM MATHEMATICAL SPACE case '\u3000': //IDEOGRAPHIC SPACE case '\u2028': //LINE SEPARATOR case '\u2029': //PARAGRAPH SEPARATOR case '\u0009': //[ASCII Tab] case '\u000A': //[ASCII Line Feed] case '\u000B': //[ASCII Vertical Tab] case '\u000C': //[ASCII Form Feed] case '\u000D': //[ASCII Carriage Return] case '\u0085': //NEXT LINE if (lastWasWS == false) //Added line { src[dstIdx++] = ch; //Added line lastWasWS = true; //Added line } continue; default: lastWasWS = false; //Added line src[dstIdx++] = ch; break; } } return new string(src, 0, dstIdx); } static readonly Regex MultipleSpaces = new Regex(@" {2,}", RegexOptions.Compiled); //Split And Join by Jon Skeet (https://stackoverflow.com/a/1280227/2352507) static string SplitAndJoinOnSpace(string input) { string[] split = input.Split(new char[] { ' '}, StringSplitOptions.RemoveEmptyEntries); return string.Join(" ", split); } //StringBuilder by user214147 (https://stackoverflow.com/a/2156660/2352507 public static string user214147(string S) { string s = S.Trim(); bool iswhite = false; int iwhite; int sLength = s.Length; StringBuilder sb = new StringBuilder(sLength); foreach (char c in s.ToCharArray()) { if (Char.IsWhiteSpace(c)) { if (iswhite) { //Continuing whitespace ignore it. continue; } else { //New WhiteSpace //Replace whitespace with a single space. sb.Append(" "); //Set iswhite to True and any following whitespace will be ignored iswhite = true; } } else { sb.Append(c.ToString()); //reset iswhitespace to false iswhite = false; } } return sb.ToString(); } //StringBuilder by fubo (https://stackoverflow.com/a/27502353/2352507 public static string fubo(this string Value) { StringBuilder sbOut = new StringBuilder(); if (!string.IsNullOrEmpty(Value)) { bool IsWhiteSpace = false; for (int i = 0; i < Value.Length; i++) { if (char.IsWhiteSpace(Value[i])) //Comparison with WhiteSpace { if (!IsWhiteSpace) //Comparison with previous Char { sbOut.Append(Value[i]); IsWhiteSpace = true; } } else { IsWhiteSpace = false; sbOut.Append(Value[i]); } } } return sbOut.ToString(); } //David S. 2013 (https://stackoverflow.com/a/16035044/2352507) public static String SingleSpacedTrim(String inString) { StringBuilder sb = new StringBuilder(); Boolean inBlanks = false; foreach (Char c in inString) { switch (c) { case '\r': case '\n': case '\t': case ' ': if (!inBlanks) { inBlanks = true; sb.Append(' '); } continue; default: inBlanks = false; sb.Append(c); break; } } return sb.ToString().Trim(); } ///  /// We want to run this item with max priory to lower the odds of /// the OS from doing program context switches in the middle of our code. /// source:https://stackoverflow.com/a/16157458 ///  /// random seed private static long ConfigProgramForBenchmarking() { //prevent the JIT Compiler from optimizing Fkt calls away long seed = Environment.TickCount; //use the second Core/Processor for the test Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2); //prevent "Normal" Processes from interrupting Threads Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High; //prevent "Normal" Threads from interrupting this thread Thread.CurrentThread.Priority = ThreadPriority.Highest; return seed; } 

}

Контрольные примечания: Режим выпуска, без приложения отладчика, процессор i7, всего 4 прогона, только проверенные короткие строки

VB.NET

 Linha.Split(" ").ToList().Where(Function(x) x <> " ").ToArray 

C #

 Linha.Split(" ").ToList().Where(x => x != " ").ToArray(); 

Наслаждайтесь мощностью LINQ = D

 Regex regex = new Regex(@"\W+"); string outputString = regex.Replace(inputString, " "); 

Наименьшее решение:

var regExp = / \ s + / g, newString = oldString.replace (regExp, ”);

Для этого не существует возможности. Вы можете попробовать следующее:

 private static readonly char[] whitespace = new char[] { ' ', '\n', '\t', '\r', '\f', '\v' }; public static string Normalize(string source) { return String.Join(" ", source.Split(whitespace, StringSplitOptions.RemoveEmptyEntries)); } 

Это приведет к удалению ведущего и завершающего whitespce, а также к коллапсу любого внутреннего пробела до одного символа пробела. Если вы действительно хотите просто свернуть пробелы, то решения, использующие регулярное выражение, лучше; в противном случае это решение будет лучше. (См. Анализ, выполненный Джоном Скитом.)

  • Как разделять строку с любыми символами пробелов как разделителями?
  • Прямоугольное соответствие Regex - Java
  • Как отключить отображение пробельных символов в среде Visual Studio
  • Чтение строки из ввода с символом пробела?
  • Как удалить повторяющиеся пробелы в строке с помощью Java?
  • Давайте будем гением компьютера.