Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>(EDIT: See bottom of post for benchmarks on different micro-optimizations of the method)</p> <p>Don't trim it - that might create a new string which you don't actually need. Instead, look through the string for any characters that <em>aren't</em> whitespace (for whatever definition you want). For example:</p> <pre><code>public static bool IsEmptyOrWhitespace(string text) { // Avoid creating iterator for trivial case if (text.Length == 0) { return true; } foreach (char c in text) { // Could use Char.IsWhiteSpace(c) instead if (c==' ' || c=='\t' || c=='\r' || c=='\n') { continue; } return false; } return true; } </code></pre> <p>You might also consider what you want the method to do if <code>text</code> is <code>null</code>.</p> <p>Possible further micro-optimizations to experiment with:</p> <ul> <li><p>Is <code>foreach</code> faster or slower than using a <code>for</code> loop like the one below? Note that with the <code>for</code> loop you can remove the "<code>if (text.Length==0)</code>" test at the start.</p> <pre><code>for (int i = 0; i &lt; text.Length; i++) { char c = text[i]; // ... </code></pre></li> <li><p>Same as above, but hoisting the <code>Length</code> call. Note that this <em>isn't</em> good for normal arrays, but <em>might</em> be useful for strings. I haven't tested it.</p> <pre><code>int length = text.Length; for (int i = 0; i &lt; length; i++) { char c = text[i]; </code></pre></li> <li><p>In the body of the loop, is there any difference (in speed) between what we've got and:</p> <pre><code>if (c != ' ' &amp;&amp; c != '\t' &amp;&amp; c != '\r' &amp;&amp; c != '\n') { return false; } </code></pre></li> <li><p>Would a switch/case be faster?</p> <pre><code>switch (c) { case ' ': case '\r': case '\n': case '\t': return false; } </code></pre></li> </ul> <p><strong>Update on Trim behaviour</strong></p> <p>I've just been looking into how <code>Trim</code> can be as efficient as this. It seems that <code>Trim</code> will only create a new string if it needs to. If it can return <code>this</code> or <code>""</code> it will:</p> <pre><code>using System; class Test { static void Main() { CheckTrim(string.Copy("")); CheckTrim(" "); CheckTrim(" x "); CheckTrim("xx"); } static void CheckTrim(string text) { string trimmed = text.Trim(); Console.WriteLine ("Text: '{0}'", text); Console.WriteLine ("Trimmed ref == text? {0}", object.ReferenceEquals(text, trimmed)); Console.WriteLine ("Trimmed ref == \"\"? {0}", object.ReferenceEquals("", trimmed)); Console.WriteLine(); } } </code></pre> <p>This means it's really important that any benchmarks in this question should use a mixture of data:</p> <ul> <li>Empty string</li> <li>Whitespace</li> <li>Whitespace surrounding text</li> <li>Text without whitespace</li> </ul> <p>Of course, the "real world" balance between these four is impossible to predict...</p> <p><strong>Benchmarks</strong> I've run some benchmarks of the original suggestions vs mine, and mine appears to win in everything I throw at it, which surprises me given the results in other answers. However, I've also benchmarked the difference between <code>foreach</code>, <code>for</code> using <code>text.Length</code>, <code>for</code> using <code>text.Length</code> once and then reversing the iteration order, and <code>for</code> with a hoisted length.</p> <p>Basically the <code>for</code> loop is very slightly faster, but hoisting the length check makes it slower than <code>foreach</code>. Reversing the <code>for</code> loop direction is very slightly slower than <code>foreach</code> too. I strongly suspect that the JIT is doing interesting things here, in terms of removing duplicate bounds checks etc.</p> <p>Code: (see <a href="http://msmvps.com/blogs/jon_skeet/archive/2009/01/26/benchmarking-made-easy.aspx" rel="noreferrer">my benchmarking blog entry</a> for the framework this is written against)</p> <pre><code>using System; using BenchmarkHelper; public class TrimStrings { static void Main() { Test(""); Test(" "); Test(" x "); Test("x"); Test(new string('x', 1000)); Test(" " + new string('x', 1000) + " "); Test(new string(' ', 1000)); } static void Test(string text) { bool expectedResult = text.Trim().Length == 0; string title = string.Format("Length={0}, result={1}", text.Length, expectedResult); var results = TestSuite.Create(title, text, expectedResult) /* .Add(x =&gt; x.Trim().Length == 0, "Trim().Length == 0") .Add(x =&gt; x.Trim() == "", "Trim() == \"\"") .Add(x =&gt; x.Trim().Equals(""), "Trim().Equals(\"\")") .Add(x =&gt; x.Trim() == string.Empty, "Trim() == string.Empty") .Add(x =&gt; x.Trim().Equals(string.Empty), "Trim().Equals(string.Empty)") */ .Add(OriginalIsEmptyOrWhitespace) .Add(IsEmptyOrWhitespaceForLoop) .Add(IsEmptyOrWhitespaceForLoopReversed) .Add(IsEmptyOrWhitespaceForLoopHoistedLength) .RunTests() .ScaleByBest(ScalingMode.VaryDuration); results.Display(ResultColumns.NameAndDuration | ResultColumns.Score, results.FindBest()); } public static bool OriginalIsEmptyOrWhitespace(string text) { if (text.Length == 0) { return true; } foreach (char c in text) { if (c==' ' || c=='\t' || c=='\r' || c=='\n') { continue; } return false; } return true; } public static bool IsEmptyOrWhitespaceForLoop(string text) { for (int i=0; i &lt; text.Length; i++) { char c = text[i]; if (c==' ' || c=='\t' || c=='\r' || c=='\n') { continue; } return false; } return true; } public static bool IsEmptyOrWhitespaceForLoopReversed(string text) { for (int i=text.Length-1; i &gt;= 0; i--) { char c = text[i]; if (c==' ' || c=='\t' || c=='\r' || c=='\n') { continue; } return false; } return true; } public static bool IsEmptyOrWhitespaceForLoopHoistedLength(string text) { int length = text.Length; for (int i=0; i &lt; length; i++) { char c = text[i]; if (c==' ' || c=='\t' || c=='\r' || c=='\n') { continue; } return false; } return true; } } </code></pre> <p>Results:</p> <pre><code>============ Length=0, result=True ============ OriginalIsEmptyOrWhitespace 30.012 1.00 IsEmptyOrWhitespaceForLoop 30.802 1.03 IsEmptyOrWhitespaceForLoopReversed 32.944 1.10 IsEmptyOrWhitespaceForLoopHoistedLength 35.113 1.17 ============ Length=1, result=True ============ OriginalIsEmptyOrWhitespace 31.150 1.04 IsEmptyOrWhitespaceForLoop 30.051 1.00 IsEmptyOrWhitespaceForLoopReversed 31.602 1.05 IsEmptyOrWhitespaceForLoopHoistedLength 33.383 1.11 ============ Length=3, result=False ============ OriginalIsEmptyOrWhitespace 30.221 1.00 IsEmptyOrWhitespaceForLoop 30.131 1.00 IsEmptyOrWhitespaceForLoopReversed 34.502 1.15 IsEmptyOrWhitespaceForLoopHoistedLength 35.690 1.18 ============ Length=1, result=False ============ OriginalIsEmptyOrWhitespace 31.626 1.05 IsEmptyOrWhitespaceForLoop 30.005 1.00 IsEmptyOrWhitespaceForLoopReversed 32.383 1.08 IsEmptyOrWhitespaceForLoopHoistedLength 33.666 1.12 ============ Length=1000, result=False ============ OriginalIsEmptyOrWhitespace 30.177 1.00 IsEmptyOrWhitespaceForLoop 33.207 1.10 IsEmptyOrWhitespaceForLoopReversed 30.867 1.02 IsEmptyOrWhitespaceForLoopHoistedLength 31.837 1.06 ============ Length=1002, result=False ============ OriginalIsEmptyOrWhitespace 30.217 1.01 IsEmptyOrWhitespaceForLoop 30.026 1.00 IsEmptyOrWhitespaceForLoopReversed 34.162 1.14 IsEmptyOrWhitespaceForLoopHoistedLength 34.860 1.16 ============ Length=1000, result=True ============ OriginalIsEmptyOrWhitespace 30.303 1.01 IsEmptyOrWhitespaceForLoop 30.018 1.00 IsEmptyOrWhitespaceForLoopReversed 35.475 1.18 IsEmptyOrWhitespaceForLoopHoistedLength 40.927 1.36 </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload