I am trying to format a string of arbitrary length into a fixed width field for display.
Let's use a width of 20 as an example, and call the string to be formatted s. I'm adding the formatted string to a StringBuilder named b.
Dim b As New System.Text.StringBuilder()
Dim s as New String
If the string I want to display is shorter than 20 characters, I can do this:
b.Append(s.PadRight(20))
or
b.AppendFormat("{0,-20}", s)
So far, so good. But, if the string is longer than 20 characters, I want the string to be truncated to 20 characters as it is appended. The code above appends the entire string.
I tried this:
b.Append(s.Substring(0,20).PadRight(20))
But, this fires an exception if the string was shorter than 20 characters.
So, I ended up with:
b.Append(s.PadRight(20).Substring(0,20))
This seems to do the job. The PadRight prevents the exception by making sure thet string has 20 characters before the Substring is performed.
I was wondering if there is an alternate method that would look more elegant and avoid padding the string just so prevent the substring from causing an exception. Have I missed a feature of String.Format that can accomplish this in one step?
Edited to add solution:
I ended up with the following code:
Module Extensions
<Extension()> _
Function AppendFixed(ByVal b As StringBuilder, ByVal s As String, ByVal width As Integer) As StringBuilder
If s.Length >= width Then
b.Append(s, 0, width)
Else
b.Append(s)
b.Append(" ", width - s.Length)
End If
Return b
End Function
End Module
This uses an extension method to clean up the syntax, as suggested by Joel and Merlyn, and uses the StringBulider Append overloads to avoid creating new strings that will have to be garbage collected, as suggested by supercat. Thanks to those that helped.
I was wondering if there is an alternate method that would look more elegant and avoid padding the string
(emphasis added)
<Extension()> _
Public Function AppendFixed(ByVal target As StringBuilder, ByVal value As String, ByVal desiredLength As Integer) As StringBuilder
If value.Length < desiredLength Then value.PadRight(desiredLength)
Return target.Append(value.Substring(0,desiredLength))
End Function
To use it:
b.AppendFixed(s, 20)
I don't think there is a more elegant way to do this. Though you could wrap this functionality into an extension method:
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()> _
Public Function AsFixedWidth(ByVal value As String, desiredLength As Integer) As String
return value.PadRight(desiredLength).Substring(0,desiredLength)
End Function
End Module
And use it like this:
b.Append(s.AsFixedWidth(20))
I would suggest that to minimize strain on the garbage collector, one should handle separately the cases where one needs to return a string from those where one needs to append a string to a StringBuilder. One should also separate out the cases where the string to be appended is shorter than needed, precisely the desired length, or longer than needed.
If one needs to return a string that's the same length as the original, just return the original string. If the string needs padding, pad it with a New String(' ', requestedLength - theString.Length)
. If it needs to be made shorter, return theString.Substring(0, requestedLength)
.
If one needs to append something to a StringBuilder and the original string is no longer than needed, append the string and then use the (char, int)
overload of Append to add padding if needed. If the original string is too long, use the (String, int, int)
overload of Append to add just the proper portion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With