.net how to compare a stringbuilder to a string
Asked Answered
S

5

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.

Siglos answered 26/8, 2014 at 13:40 Comment(1)
this is only vb, please remove the c# tagLindell
B
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
Beeves answered 26/8, 2014 at 13:42 Comment(10)
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.Siglos
@user1771315: yes, StringBuilder.ToString creates another string in memory even if this answer suggests the opposite. I've looked at the source. referencesource.microsoft.com/#mscorlib/system/text/…Verlie
@user1771315: here's an article about StringBuilder.ToString: dotnetperls.com/stringbuilder-tostring So it seems not that clear that it needs to allocate a new string in memory.Verlie
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:Siglos
@user1771315: i've also tested it. ToString: 00:00:00.317 SbEquals: 00:00:02.583Verlie
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 memorySiglos
@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.Verlie
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.Siglos
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.Beeves
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.Siglos
R
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.

Riparian answered 26/8, 2014 at 13:41 Comment(0)
S
0

A StringBuilder has a ToString() method.

in C#:

StringBuilder sb = new StringBuilder("test");
if (sb.ToString() == "test")
{
    // code here
}
Slag answered 26/8, 2014 at 13:42 Comment(0)
A
-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;
}
Amp answered 28/10, 2018 at 15:55 Comment(3)
Why do you pass the string by reference?Towny
I do it to reduce garbage collectingAmp
How does it reduce garbage collection? Wouldn't the string instance be the same anyway?Towny
S
-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

Siglos answered 26/8, 2014 at 14:25 Comment(4)
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.Beeves
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()Siglos
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 (?)Siglos
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.Beeves

© 2022 - 2024 — McMap. All rights reserved.