2

In vb.net (or C#) I can't figure out how to compare a stringbuilder to a string. I have searched quite a bit and can't find the answer. I had to write my own routine. Isn't there a better way?

This doesn't work:

Dim s As String = "abc"
Dim sb As New StringBuilder("abc")
If sb.Equals(s) Then
  Console.WriteLine(sb.ToString() + " DOES equal " + s)
Else
  Console.WriteLine(sb.ToString() + " does NOT equal " + s)
End If

Results of that code is: abc does NOT equal abc

Isn't there some way of comparing a stringbuilder to a string without writing my own routine? It's probably something obvious that I'm missing since I can't find this question anywhere.

phuclv
  • 37,963
  • 15
  • 156
  • 475
munge
  • 73
  • 1
  • 12

5 Answers5

5

The simplest way is to get the content of the StringBuilder as a string:

If sb.ToString() = s Then ...

If you want to avoid creating that string (perhaps for memory usage concerns), I am afraid that you have to write your own routine to compare them. Basically something like:

Public Shared Function SbEquals(sb As StringBuilder, s As String) As Boolean
  If sb.Length <> s.Length Then Return False
  For i As Integer = 0 to s.Length - 1
    If sb(i) <> s(i) Return False
  Next
  Return True
End Function
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Well I got 4 answers in less that 10 minutes, stackoverflow is awesome! Thanks for that, the routine you gave me was better than mine so I used it instead. The whole idea of using a stringbuilder was to avoid creating strings in memory, so the "sb.tostring() = s" isn't what I want, BUT that brings up another question. Does the stringbuilder tostring() method really create another string in memory? Because I read somewhere maybe it doesn't. I guess that should be a separate question. – munge Aug 26 '14 at 13:56
  • @user1771315: yes, `StringBuilder.ToString` creates another string in memory even if [this answer](http://stackoverflow.com/a/1359976/284240) suggests the opposite. I've looked at the source. http://referencesource.microsoft.com/#mscorlib/system/text/stringbuilder.cs#5a97da49a158a3c9#references – Tim Schmelter Aug 26 '14 at 14:02
  • @user1771315: here's an article about `StringBuilder.ToString`: http://www.dotnetperls.com/stringbuilder-tostring So it seems not that clear that it needs to allocate a new string in memory. – Tim Schmelter Aug 26 '14 at 14:10
  • OK I had to spend the time to prove this for myself, but my own routine (it WAS Guffa's routine!) is faster than tostring(), but not by much: – munge Aug 26 '14 at 14:12
  • @user1771315: i've also tested it. `ToString`: 00:00:00.317 `SbEquals`: 00:00:02.583 – Tim Schmelter Aug 26 '14 at 14:14
  • OK I had to spend the time to prove this for myself, but my own routine (it WAS Guffa's routine!) is faster than tostring(), but not by much. Run guffa's routine 10 million times took 468 milliseconds, run a compare with toString() took 943 MS. I would expect making a new string 10 million times would take longer. So I tried that, and making a new string 10 million times only took 123 ms. (I wonder if I'm doing something wrong here..) So it seems like, yes, stringbuilder tostring() is actually making a string in memory – munge Aug 26 '14 at 14:18
  • @user1771315: it depends on many factors, for example the string length and if they are equal or not. My test is also just one perspective. Fyi, i've used a string with length 200 and a loop with 1000000 iterations, the string was equal to the stringbuilder. Then `ToString` was always ~8 times faster than guffas method. – Tim Schmelter Aug 26 '14 at 14:24
  • I changed my code (shown below) to use a string 200 characters long, toString() took 16,072ms and my/Guffa's routine took 14,349ms. So the difference is smaller because most of the time is spent going through the 200 characters, but toString() is still slower. – munge Aug 26 '14 at 14:41
  • The `StringBuilder` used to return the internal buffer as a string, so that would not create a new string (but it would create a new internal buffer if you kept changing the `StringBuilder`). The implementation was changed to use chunks of characters instead one large buffer, and the `ToString` method naturally had to be changed to create a new string from the chunks. – Guffa Aug 26 '14 at 14:49
  • Tim you are right Guffa pointed out, in my code I forgot to reset the dang stopwatch. Once I did that, the toString() is way faster, just like your results. – munge Aug 26 '14 at 18:21
0

Use

if sb.ToString() = s Then

Currently you are comparing StringBuilder instance to string and not their values. To get the value of StringBuilder object, you have to call ToString and then you can compare it with a string.

Habib
  • 219,104
  • 29
  • 407
  • 436
0

A StringBuilder has a ToString() method.

in C#:

StringBuilder sb = new StringBuilder("test");
if (sb.ToString() == "test")
{
    // code here
}
David Crowell
  • 3,711
  • 21
  • 28
-1

A simple c# solution (middle road performance)

public static bool EqualStrings(StringBuilder stringBuilder, ref string text)
{
    return stringBuilder.Length == text.Length && stringBuilder.ToString() == text;
}
vikingfabian
  • 451
  • 5
  • 5
-2

Here's my code for the tostring() test versus my own routine:

Sub speedTest1()

Dim time As New System.Diagnostics.Stopwatch
time.Start()
Dim i As Integer
Dim sb As New StringBuilder("abc")
Dim s As String = "abc"
For i = 0 To 10000000
  equalsString(sb, s)
Next
time.Stop()
Console.WriteLine(CStr(time.ElapsedMilliseconds) + " MS for my own routine")

time.Start()
For i = 0 To 10000000
  equalsString2(sb, s)
Next
time.Stop()
Console.WriteLine(CStr(time.ElapsedMilliseconds) + " MS for tostring()")

End Sub

Function equalsString(pSB As StringBuilder, pStr As String) As Boolean

If pSB.Length <> pStr.Length Then Return False
For i As Integer = 0 To pStr.Length - 1
  If pSB(i) <> pStr(i) Then
    Return False
  End If
Next
Return True

End Function

Function equalsString2(pSb As StringBuilder, pStr As String) As Boolean

Return (pSb.ToString() = pStr)

End Function

And the result is: 527 MS for my own routine 1045 MS for tostring()

I can't get the stupid ctrl-k to work in here, but that's how I got my results

munge
  • 73
  • 1
  • 12
  • You need to reset the stopwatch between the tests, otherwise the time for the second test is added to the time for the first test. The times would be 527 ms and 518 ms. – Guffa Aug 26 '14 at 14:54
  • Duh do I feel stupid. OH thank you once again. Based on that, toString() is WAY faster. 15,070ms for our routine versus 1859 MS for toString() – munge Aug 26 '14 at 18:19
  • I'm wrong again, OK now I have the definitive answer, for a long string, (200 bytes), toString is WAY faster. For a VERY short string, our routine is faster. Somehow the internal comparing done by .net is faster than our code, which must outweigh the overhead of creating/deleting string variables (?) – munge Aug 26 '14 at 18:26
  • That sounds reasonable, the internal string comparison is optimised using pointers. Consider however that measuring the execution time doesn't give the whole picture on performance, creating a lot of strings will affect memory usage and garbage collections. – Guffa Aug 26 '14 at 19:17