I’m currently working on a website that needs a URL shortener. In order to have a good shortened URL I must make the most of the path after the domain. The common way to do this, as Bit.ly and others already do, is to have a mix of alphanumeric characters that increment each time a new URL has been created. I’m using Asp.Net and since there’s no built in function or an already published one, I created my own.
This function works by accepting a list of characters to use in the counting process. Each time a new value is needed the function increments the count by going to the next character in the array. I hope to have a lot of traffic so it’s important to be efficient and fast. The resulting code can run thousands of times in just a fraction of a second.
To use the function you need to pass in the current value (or empty string “” if it’s the first time) and a character array of values to use (include lowercase and uppercase values if you want to have case sensitivity). Including lowercase letters adds an enormous amount of extra values in a shorter character span. That’s very important when you’re working with short URLs.
Function CountWithCharacters(ByVal strValueCurrent As String, ByVal aryCharacter() As Char) As String
Dim chrCharacterCurrent As Char
Dim chrCharacterNew As Char
Dim blnIncrementParent As Boolean
Dim intCharacterCurrent As Integer = strValueCurrent.Length
Dim strReturnValue As String
strReturnValue = strValueCurrent
Do
'reset the IncrementParent switch
blnIncrementParent = False
'decrement the current character place so it moves up to the parent
intCharacterCurrent -= 1
'Are we still looking at characters that exist?
If intCharacterCurrent >= 0 Then
chrCharacterCurrent = strReturnValue.Substring(intCharacterCurrent, 1)
'If the current character is the same as the last value in the array we must increment the parent
'and set its value to the first value in the array
If chrCharacterCurrent = aryCharacter(aryCharacter.Length - 1) Then
If intCharacterCurrent >= 0 Then
blnIncrementParent = True
chrCharacterNew = aryCharacter(0)
Else
chrCharacterNew = Nothing
End If
Else
'take the next value
chrCharacterNew = aryCharacter(Array.IndexOf(aryCharacter, chrCharacterCurrent) + 1)
End If
'Remove the current character and replace it with the new one
strReturnValue = strReturnValue.Remove(intCharacterCurrent, 1).Insert(intCharacterCurrent, chrCharacterNew)
Else
'Trying to increment a value that doesn't exist. Instead append the first value in the character array
strReturnValue = aryCharacter(0) & strReturnValue
End If
Loop While blnIncrementParent
Return strReturnValue
End Function
Using the function
After calling the following example the result will be a value of 0 since it’s passing in an empty string and 0 is the first value in the character array. I’m creating the character array by using a string and converting it as I pass it into the function. This character array can include any set of characters in any order. I’m using numbers, lowercase letters, uppercase letters and finally _, – and ~. I’m using those three extra characters to give me more values in a smaller character span. It’s important that all these characters don’t have to be URL encoded which would actually make the URL longer.
strValue = CountWithCharacters("", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-~".ToCharArray)
As I continue to use the function, feeding it the previous result so it can increment it, I’ll get values like 1, 2, 3, … a, b, c, …A, B, C, … _, -, ~. After the ~ value the function will return 00, 01, 02 and so on. The following call will return 0Az to strValue.
strValue = CountWithCharacters("0Ay", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-~".ToCharArray)
Profanity
As I worked on this function it crossed my mind that I would eventually run into some curse words. As the values increment, the letter combinations will spell words like ass, shit, fuck, etc. Users will probably not appreciate me giving them a URL that contains curse words. To prevent this I created another function that skips past any words I specify. This skipping process can take a tiny fraction of a second or much longer, depending on how many characters need to be skipped. Once I hit 5+ characters it can take over 1 second to execute. That’s a lot of time for a single function but given how infrequently it needs to skip past a word and now long it’ll take me to reach 5 character URL (”00000″ is the equivalent of 17,850,626), I was willing to forgive it and move on.
Function CountWithCharacters(ByVal strValueCurrent As String, ByVal aryCharacter() As Char, ByVal arySkipWords() As String) As String
Dim strReturnValue As String
Dim blnSkip As Boolean
Dim strSkipWord As String
strReturnValue = strValueCurrent
Do
blnSkip = False
strReturnValue = CountWithCharacters(strReturnValue, aryCharacter)
For Each strSkipWord In arySkipWords
If strReturnValue.ToLower.Contains(strSkipWord) Then
blnSkip = True
Exit For
End If
Next
Loop While blnSkip
Return strReturnValue
End Function
This new function will execute the previous one and then check it for a skip word. If it finds a skip word then it’ll keep looping until the counter incremented past it. This design probably isn’t the most efficient one but I didn’t want to spend any more time on something so simple. It’s better to move on and revisit it if the site gets popular enough for me to be concerned.
Here’s an example call to the function. It passes in the value “asr” which would normally return “ass” but instead, since “ass” is included in the skip word array, “ast” will be the return value.
strValue = CountWithCharacters("asr", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-~".ToCharArray, "shit,piss,fuck,cunt,cock,dick,tit,ass".Split(","))
