A Million Little Pieces Of My Mind

NamtiraLib

SuperStrings

By: Paul S Cilwa Posted: 4/10/2026 Page Views: 44
Hashtags: #Namtira #VisualBasic #VBNET #ClassLibrary #NamtiraLib #SuperStrings
Creating extension methods to the String object type.
Estimated reading time: 9 minute(s) (2103 words)

The low-level classes provided by .NET are nevertheless very powerful. However, they inexplicably omit some equally basic, and very useful properties and methods. While the effect of these missing elements can be performed by another combination of elements, doing so doesn't usually make for more readable code. And that's where extension methods and properties come in.

Module SuperStrings
MemberParametersExample
SafemyObj.Safe"" if Nothing
LeftLength As Int16"Hello".Left(3)"Hel"
RightLength As Int16"Hello".Right(3)"llo"
MidStart As Int16, Length As Int16 (optional)"Hello".Mid(2, 3)"ell"
IndexOfSearchFor As String, Direction As SearchDirection (optional)"abcabc".IndexOf("b", SearchDirection.Right2Left)
RemoveRemoveThese As Char() or RemoveThis As String"a-b-c".Remove("-")"abc"
EnquoteQ As String (optional) or Q1, Q2 As String"Hi".Enquote""Hi""
DequoteQ As String (optional) or Q1, Q2 As String""Hi"".Dequote"Hi"
LCase"Hello".LCase"hello"
UCase"Hello".UCase"HELLO"
TitleCase"hello world".TitleCase"Hello World"
SentenceCase"hello world".SentenceCase"Hello world"
ToBool"Yes".ToBoolTrue
WrapLineLength As Integer (optional, default 70)longText.Wrap(40)
ToHtml"A & B".ToHtml"A & B"
FromHtml"A & B".FromHtml"A & B"
ToJScript"He said "hi"".ToJScript
FromJScriptjsText.FromJScript
TrimCleandirtyText.TrimClean
StripAnchorTagshtml.StripAnchorTags
SwapByRef a, ByRef bSwap(x, y)
Constants
vbQuotevbQuote"

Open the new NamtiraLib project (if it isn't already open). Since this is the first module, created by default, we need to change "Class Class1" to "Module SuperStrings", in both the file and the filename, itself.

For those who don't like to type, here is the actual so-far contents of SuperStrings.vb.

Imports System.Runtime.CompilerServices Imports System.IO Imports System.Globalization Module SuperStrings End Module

Substrings

It's easy to confuse the String class with the SuperStrings module, but they are quite distinct. The String class includes many useful methods, but no ability to return a substring of itself. For that, the programmer must use functions from the SuperStrings module.

This is not, of course, an object-oriented approach. Luckily, it's easily remedied with a few extension methods.

Public Module SuperStrings <Extension()> Public Function Safe(ByVal Value) As String If Value Is Nothing Then Return String.Empty Else Return Value.ToString End If End Function <Extension()> Public Function Left(ByVal Value As String, ByVal Length As Int16) As String Return Strings.Left(Value.Safe, Length) End Function <Extension()> Public Function Right(ByVal Value As String, ByVal Length As Int16) As String Return Strings.Right(Value.Safe, Length) End Function <Extension()> Public Function Mid(ByVal Value As String, ByVal Start As Int16, Optional ByVal Length As Int16 = 0) As String If Length = 0 Then Return Strings.Mid(Value.Safe, Start) Else Return Strings.Mid(Value.Safe, Start, Length) End If End Function End Module

The Safe extension method actually works on any data type. Some return values like Null that will throw an exception. By running all values through the Safe method before otherwise working on them, we can avoid such an embarrassing result.

Left, Right, and Mid simply pass on the arguments to the appropriate Strings functions. This is a very small amount of work at this level, to prevent a lot of extra typing later.

Searching and Removing

The built-in IndexOf method only searches left-to-right. Our extension adds an optional Direction parameter, using a custom SearchDirection enum, so we can also search right-to-left.

Enum SearchDirection Left2Right Right2Left End Enum <Extension()> Public Function IndexOf(Item As String, SearchFor As String, Optional Direction As SearchDirection = SearchDirection.Left2Right) As Int16 If Direction = SearchDirection.Right2Left Then Item = Item.Reverse SearchFor = SearchFor.Reverse End If Return Item.IndexOf(SearchFor) - Item.Length + 1 End Function

Similarly, removing characters or substrings from a string is a common operation that doesn't need to be verbose. The Remove extension has two overloads: one that removes every character in a given array of characters, and another that removes all occurrences of a given substring.

<Extension()> Public Function Remove(Item As String, RemoveThese As Char()) As String For Each C As Char In RemoveThese Item = Item.Replace(C, "") Next Return Item End Function <Extension()> Public Function Remove(Item As String, RemoveThis As String) As String Return Item.Replace(RemoveThis, "") End Function

Quoted Strings

I find I often need to apply quotes to a string, or to remove them. The String class doesn't provide a shortcut for these functions, but we can extend the class by adding three methods and a constant.

Module SuperStrings . . . Public Const vbQuote As String = """" <Extension()> Public Function Enquote(ByVal Value As String, Optional ByVal Q As String = vbQuote) As String Value = Value.Safe.Replace(Q, Q + Q) Return Q + Value.Safe + Q End Function <Extension()> Public Function Dequote(ByVal Value As String, Optional ByVal Q As String = vbQuote) As String Value = Value.Safe If Value.Left(1) = Q And Value.Right(1) = Q Then Value = Value.Mid(2, Value.Length - 2) Value = Value.Safe.Replace(Q + Q, Q) End If Return Value End Function End Module

Our constant, vbQuote, provides one I swear was in the older versions of Visual Basic.

The Enquote method more than simply concatenates a quote with the string and another quote. First, it checks and doubles any internal quotes, thus creating a proper Visual Basic quoted string.

Similarly, the Dequote method, first checking to ensure that this is, in point of fact, a quoted string. If it is, the enclosing quotes are removed, and any embedded double-quotes, replace with singles, thus restoring the original string.

Also, please note that any character can be used as "quotes"; the second argument to each method is optional, and only defaults to vbQuote.

There are also overloads of Enquote and Dequote that accept distinct opening and closing quote characters—useful when working with parentheses, brackets, or other asymmetric delimiters.

<Extension()> Public Function Enquote(Value As String, Q1 As String, Q2 As String) As String Return Q1 + Value.Safe + Q2 End Function <Extension()> Public Function Dequote(Value As String, Q1 As String, Q2 As String) As String If Value.Left(1) = Q1 And Value.Right(1) = Q2 Then Value = Value.Mid(2, Value.Length - 2) End If Return Value End Function

Modifying Case

Upper case? Lower case? These are easy extensions making use of the Strings module, as we did earlier with substrings. Title case and sentence case are slightly trickier.

Module SuperStrings . . . <Extension()> Public Function LCase(ByVal Value As String) As String Return Strings.LCase(Value.Safe) End Function <Extension()> Public Function UCase(ByVal Value As String) As String Return Strings.UCase(Value.Safe) End Function <Extension()> Public Function TitleCase(ByVal Value As String) As String Return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Value.Safe) End Function <Extension()> Public Function SentenceCase(ByVal Value As String) As String Return Value.Safe.Left(1).UCase + Value.Safe.Mid(2).LCase End Function End Module

Fail-safe Boolean

VB provides internal conversions to and from String objects and Boolean (true/false) objects. However, these conversions are simplistic and don't cover all data types. Thus we provide a ToBool method:

Module SuperStrings . . . <Extension()> Public Function ToBool(ByVal Value) As Boolean If Value Is Nothing Then Return False End If If VarType(Value) = vbBoolean Then Return Value End If If VarType(Value) = vbInteger Or VarType(Value) = vbLong Then Return If(Value = 0, False, True) End If If VarType(Value) = vbString Then Value = Value.Safe.Trim End If Select Case Value.Ucase Case "TRUE", "YES", "ON", "1", "T", "Y" ToBool = True Case Else ToBool = False End Select End Function End Module

Wrapping Text

Another obvious, but omitted, function that we might ask of text is wrapping—that is, if the text contains more than some arbitrary number of characters (say, 70), it should be split between words into multiple lines so that none exceed that limit.

<Extension()> Public Function Wrap(ByVal Text As String, Optional ByVal LineLength As Integer = 70) As String Text = Text.Trim.Replace(vbCrLf, " ").Replace(vbCr, " ").Replace(vbLf, " ").Replace(vbTab, " ") Dim Words As String() = Text.Split(" ") Dim i As Integer = 0 Dim Line As New StringBuilder With New StringBuilder While i < Words.Count If i > 0 Then .AppendLine() While (i < Words.Count) AndAlso (Line.Length + Words(i).Length + 1) < LineLength If Line.Length > 0 Then Line.Append(" ") End If Line.Append(Words(i)) i += 1 End While .Append(Line.ToString) Line.Clear() End While Return .ToString() End With End Function

HTML Conversions

If you've worked with websites at all, you know that there are a number of characters that are supposed to be represented by special HTML-specific substitutes. For example, since both the quote and double-quote characters are used in HTML tags to specify option values, you can't just plop text onto a web page's HTML if it contains any of these characters.

SuperStrings to the rescue! The ToHtml extension will convert plain text to its HTML-safe equivalent.

<Extension()> Public Function ToHtml(ByVal PlainText As String) As String PlainText = PlainText.Replace("\""", "—SuperString=vbQuote—") PlainText = PlainText.Replace("\'", "—SuperString=vbApos—") PlainText = PlainText.Replace("&", "&amp;") PlainText = PlainText.Replace("—", "&mdash;") PlainText = PlainText.Replace("—", "&mdash;") PlainText = PlainText.Replace(ChrW(150), "&mdash;") PlainText = PlainText.Replace("é", "&eacute;") PlainText = PlainText.Replace(vbQuote, "&quot;") PlainText = PlainText.Replace(ChrW(8220), "&quot;") PlainText = PlainText.Replace(ChrW(8221), "&quot;") PlainText = PlainText.Replace("'", "&apos;") PlainText = PlainText.Replace("…", "&hellip;") PlainText = PlainText.Replace("…", "&hellip;") PlainText = PlainText.Replace("½", "&frac12;") PlainText = PlainText.Replace("¼", "&frac14;") PlainText = PlainText.Replace("¾", "&frac34;") PlainText = PlainText.Replace("ï", "&iuml;") PlainText = PlainText.Replace("™", "&trade;") PlainText = PlainText.Replace("\", "&#92;") PlainText = PlainText.Replace(vbCr, "&#13;") PlainText = PlainText.Replace(vbLf, "&#10;") PlainText = PlainText.Replace(vbTab, "&#9;") PlainText = PlainText.Replace("—SuperString=vbQuote—", "\""") PlainText = PlainText.Replace("—SuperString=vbApos—", "\'") Return PlainText End Function

Similarly, the FromHtml extension will convert an HTML-friendly block of text back into plain text.

<Extension()> Public Function FromHtml(ByVal HtmlText As String) As String HtmlText = HtmlText.Replace("&amp;", "&") HtmlText = HtmlText.Replace("&mdash;", "—") HtmlText = HtmlText.Replace("&eacute;", "é") HtmlText = HtmlText.Replace("&quot;", """") HtmlText = HtmlText.Replace("&apos;", "'") HtmlText = HtmlText.Replace("&hellip;", "…") HtmlText = HtmlText.Replace("&frac12;", "½") HtmlText = HtmlText.Replace("&frac14;", "¼") HtmlText = HtmlText.Replace("&frac34;", "¾") HtmlText = HtmlText.Replace("&iuml;", "ï") HtmlText = HtmlText.Replace("&trade;", "™") HtmlText = HtmlText.Replace("&#92;", "\") HtmlText = HtmlText.Replace("&#13;", vbCr) HtmlText = HtmlText.Replace("&#10;", vbLf) HtmlText = HtmlText.Replace("&#9;", vbTab) Return HtmlText End Function

And Then There Are JScript Strings

A situation that is similar in form but distinct in details comes when you're working on some Java, Javascript, or JScript code and need to insert some text with punctuation or other special characters in it. For the same reason as above with HTML text, we need to be able to convert plain text back and forth from Jscript-friendly text.

<Extension()> Public Function ToJScript(PlainText As String) As String Dim i As Int16 Dim Result As String = String.Empty For i = 1 To PlainText.Length Select Case PlainText(i - 1) Case """" Result += "\""" Case "'" Result += "\'" Case "\" Result += "\\'" Case vbCr Result += "\n" Case vbLf Result += "\f" Case vbTab Result += "\t" Case Else Result += PlainText(i - 1) End Select Next Return Result End Function <Extension()> Public Function FromJScript(ByVal JavaText As String) As String JavaText = JavaText.Replace("\""", """") JavaText = JavaText.Replace("\'", "'") JavaText = JavaText.Replace("\\", "\") JavaText = JavaText.Replace("\n", vbCr) JavaText = JavaText.Replace("\f", vbLf) JavaText = JavaText.Replace("\t", vbTab) Return JavaText End Function

Cleaning Up Text

Sometimes you receive text from external sources that contains stray carriage returns, line feeds, and tabs that you'd rather not have. The TrimClean extension strips all carriage returns and line feeds, replaces tabs with spaces, and trims the result.

<Extension> Public Function TrimClean(Source As String) As String Return Source.Replace(vbCr, "").Replace(vbLf, "").Replace(vbTab, " ").Trim() End Function

Stripping Anchor Tags

When you need to extract plain text from HTML but want to preserve everything except the anchor tags themselves, StripAnchorTags uses regular expressions to remove both the opening <a> and closing </a> tags while leaving the link text intact.

<Extension> Function StripAnchorTags(Input As String) As String Dim Result As String = Regex.Replace(Input, "<a\b[^>]*>", "", RegexOptions.IgnoreCase) Result = Regex.Replace(Result, "</a>", "", RegexOptions.IgnoreCase) Return Result End Function

Swapping Variables

A classic utility that doesn't belong to any particular type but earns its keep everywhere: Swap exchanges the values of two variables by reference. Note that this is a Sub, not an extension method, since it operates on a pair of values rather than extending a single type.

Public Sub Swap(ByRef a, ByRef b) Dim Temp Temp = b b = a a = Temp End Sub