Comment remplacer plusieurs espaces blancs par un espace blanc

Disons que j’ai une chaîne telle que:

"Hello how are you doing?" 

Je voudrais une fonction qui transforme plusieurs espaces en un seul espace.

Donc j’aurais:

 "Hello how are you doing?" 

Je sais que je pourrais utiliser regex ou appeler

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

Mais je devrais l’appeler plusieurs fois pour m’assurer que tous les espaces séquentiels sont remplacés par un seul.

Y a-t-il déjà une méthode intégrée pour cela?

 ssortingng cleanedSsortingng = System.Text.RegularExpressions.Regex.Replace(dirtySsortingng,@"\s+"," "); 

Cette question n’est pas aussi simple que d’autres affiches l’ont fait ressortir (et comme je le croyais à l’origine) – parce que la question n’est pas tout à fait précise.

Il y a une différence entre “espace” et “espace blanc”. Si vous voulez seulement dire des espaces, vous devriez utiliser une expression régulière de " {2,}" . Si vous voulez dire un espace, c’est différent. Tous les espaces doivent- ils être convertis en espaces? Que devrait-il arriver à l’espace au début et à la fin?

Pour le benchmark ci-dessous, je suppose que vous ne vous souciez que des espaces, et que vous ne voulez rien faire pour les espaces individuels, même au début et à la fin.

Notez que l’exactitude est presque toujours plus importante que la performance. Le fait que la solution Split / Join supprime tout espace de début / fin (même les espaces simples) est incorrect en ce qui concerne vos exigences spécifiées (qui peuvent bien sûr être incomplètes).

Le benchmark utilise MiniBench .

 using System; using System.Text.RegularExpressions; using MiniBench; internal class Program { public static void Main(ssortingng[] 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(bigSsortingng, normalized); suite.Display(ResultColumns.All, suite.FindBest()); } private static readonly Regex MultipleSpaces = new Regex(@" {2,}", RegexOptions.Comstackd); static ssortingng NormalizeWithRegex(ssortingng input) { return MultipleSpaces.Replace(input, " "); } // Guessing as the post doesn't specify what to use private static readonly char[] Whitespace = new char[] { ' ' }; static ssortingng NormalizeWithSplitAndJoin(ssortingng input) { ssortingng[] split = input.Split (Whitespace, SsortingngSplitOptions.RemoveEmptyEnsortinges); return ssortingng.Join(" ", split); } } 

Quelques tests:

 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 

Ici, le premier nombre est le nombre d’itérations, le second est le temps écoulé et le troisième est un score mis à l’échelle, 1,0 étant le meilleur.

Cela montre que dans au moins certains cas (y compris celui-ci), une expression régulière peut surpasser la solution Split / Join, parfois avec une marge très importante.

Cependant, si vous passez à une exigence “tout espace”, alors Split / Join semble gagner. Comme souvent, le diable est dans le détail …

Bien que les réponses existantes soient correctes, j’aimerais souligner une approche qui ne fonctionne pas :

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

Cela peut boucler pour toujours. Quelqu’un a envie de deviner pourquoi? (Je ne suis tombé que sur une question posée il y a quelques années en tant que question d’un groupe de discussion … quelqu’un a effectivement rencontré le problème.)

Un expressoin régulier serait le moyen le plus simple. Si vous écrivez la regex correctement, vous n’aurez pas besoin de plusieurs appels.

Changez la en ceci:

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

Comme déjà souligné, cela se fait facilement par une expression régulière. J’appendai simplement que vous voudrez peut-être append un .sortingm () à cela pour vous débarrasser des espaces de début et de fin.

Voici la solution avec laquelle je travaille. Sans RegEx et Ssortingng.Split.

 public static ssortingng TrimWhiteSpace(this ssortingng Value) { SsortingngBuilder sbOut = new SsortingngBuilder(); if (!ssortingng.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(); } 

afin que vous puissiez:

 ssortingng cleanedSsortingng = dirtySsortingng.TrimWhiteSpace(); 

Je partage ce que j’utilise, car il semble que j’ai proposé quelque chose de différent. Je l’utilise depuis un moment et c’est assez rapide pour moi. Je ne sais pas comment cela se compare aux autres. Je l’utilise dans un graveur de fichier délimité et j’exécute de grandes bases de données un champ à la fois.

  public static ssortingng NormalizeWhiteSpace(ssortingng S) { ssortingng s = S.Trim(); bool iswhite = false; int iwhite; int sLength = s.Length; SsortingngBuilder sb = new SsortingngBuilder(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.ToSsortingng()); //reset iswhitespace to false iswhite = false; } } return sb.ToSsortingng(); } 

En utilisant le programme de test que Jon Skeet a posté, j’ai essayé de voir si je pouvais faire une boucle manuscrite plus rapidement.
Je peux battre NormalizeWithSplitAndJoin à chaque fois, mais seulement battre NormalizeWithRegex avec des entrées de 1000, 5.

 static ssortingng NormalizeWithLoop(ssortingng input) { SsortingngBuilder output = new SsortingngBuilder(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(); } 

Je n'ai pas regardé le code machine produit par la gigue, mais je pense que le problème est le temps pris par l'appel à SsortingngBuilder.Append () et que faire beaucoup mieux nécessiterait l'utilisation d'un code non sécurisé.

Donc, Regex.Replace () est très rapide et difficile à battre!

Un dissolvant rapide supplémentaire de blanc … C’est le plus rapide et est basé sur la copie sur place de Felipe Machado.

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

Les benchmarks ...

InPlaceCharArraySpaceOnly par Felipe Machado sur CodeProject 2015 et modifié par Sunsetquest pour la suppression de plusieurs espaces. Temps: 3,75 Tiques

InPlaceCharArray par Felipe Machado 2015 et légèrement modifié par Sunsetquest pour le retrait multi-espace. Temps 6.50 Ticks (supporte également les tabs)

SplitAndJoinOnSpace par Jon Skeet . Heure: 13h25

SsortingngBuilder par fubo Heure: 13.5 Ticks (prend également en charge les tabs)

Regex avec comstack par Jon Skeet . Temps: 17 Ticks

SsortingngBuilder by David S 2013 Durée: 30.5 Ticks

Regex avec non-compilation par Brandon Time: 63.25 Ticks

SsortingngBuilder par user214147 Heure: 77.125 Ticks

Regex avec Tim Hoolihan temps non compilé : 147.25 Ticks

Le code de référence ...

 using System; using System.Text.RegularExpressions; using System.Diagnostics; using System.Threading; using System.Text; static class Program { public static void Main(ssortingng[] args) { long seed = ConfigProgramForBenchmarking(); Stopwatch sw = new Stopwatch(); ssortingng warmup = "This is a Warm up function for best benchmark results." + seed; ssortingng input1 = "Hello World, how are you doing?" + seed; ssortingng input2 = "It\twas\t \tso nice to\t\t see you \tin 1950. \t" + seed; ssortingng correctOutput1 = "Hello World, how are you doing?" + seed; ssortingng correctOutput2 = "It\twas\tso nice to\tsee you in 1950. " + seed; ssortingng 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-Ssortingn) 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-Ssortingn) 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-comstack Tim Hoolihan (https://stackoverflow.com/a/1279874/2352507) ssortingng cleanedSsortingng = 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 comstack 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 comstack 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 ")); //SsortingngBuilder by user214147 (https://stackoverflow.com/a/2156660/2352507 output1 = user214147(warmup); sw.Restart(); output1 = user214147(input1); output2 = user214147(input2); sw.Stop(); Console.WriteLine("SsortingngBuilder by user214147: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //SsortingngBuilder by fubo (https://stackoverflow.com/a/27502353/2352507 output1 = fubo(warmup); sw.Restart(); output1 = fubo(input1); output2 = fubo(input2); sw.Stop(); Console.WriteLine("SsortingngBuilder by fubo: " + (sw.ElapsedTicks - baseVal)); Console.WriteLine(" Trial1:(spaces only) " + (output1 == correctOutput1 ? "PASS " : "FAIL ")); Console.WriteLine(" Trial2:(spaces+tabs) " + (output2 == correctOutput2 ? "PASS " : "FAIL ")); //SsortingngBuilder 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("SsortingngBuilder(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-Ssortingn) static ssortingng InPlaceCharArray(ssortingng 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 Comstackr 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; } 

}

Notes de référence: Mode de publication, sans débogueur attaché, processeur i7, moyenne de 4 exécutions, seulement de courtes chaînes testées

VB.NET

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

C #

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

Profitez de la puissance de LINQ = D

 Regex regex = new Regex(@"\W+"); ssortingng outputSsortingng = regex.Replace(inputSsortingng, " "); 

La plus petite solution:

var regExp = / \ s + / g, newSsortingng = oldSsortingng.replace (regExp, ”);

Il n’y a aucun moyen de faire cela. Vous pouvez essayer ceci:

 private static readonly char[] whitespace = new char[] { ' ', '\n', '\t', '\r', '\f', '\v' }; public static ssortingng Normalize(ssortingng source) { return Ssortingng.Join(" ", source.Split(whitespace, SsortingngSplitOptions.RemoveEmptyEnsortinges)); } 

Cela supprimera les blancs de début et de fin et réduira tout espace interne en un seul caractère d’espacement. Si vous ne voulez vraiment que réduire les espaces, les solutions utilisant une expression régulière sont meilleures; sinon cette solution est meilleure. (Voir l’ parsing faite par Jon Skeet.)