8
\$\begingroup\$

This is a simple utility, intended to sit on the desktop for when needed, that does the simple ROT13 encoding and decoding.

I am used to coding in VBA, and I am interested in more .Net idiomatic coding styles.

Public Class Rot13Decoder

    Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles txtRotEntry.TextChanged
        lblResult.Text = Rot13(txtRotEntry.Text)
    End Sub

    Function Rot13(Source As String) As String
        Dim i As Long
        Dim result As String = ""

        For i = 0 To Source.Length - 1
            Dim myChar As Char
            myChar = Source.Substring(i, 1)

            Select Case myChar ' originally used Asc(Source(i)), hence the integers below
                Case "a" To "m", "A" To "M" '65 To 77, 97 To 109
                    result &= Chr(Asc(myChar) + 13) 'Chr(Asc(Source(i)) + 13)
                Case "n" To "z", "N" To "Z" '78 To 90, 110 To 122
                    result &= Chr(Asc(myChar) - 13) 'Chr(Asc(Source(i)) - 13)
                Case Else
                    result &= myChar
            End Select
        Next

        Return result
    End Function

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

    End Sub
End Class

Sample use

(The title of the form says decoder, and I am using it in the example to encode!)

Double clicking on the form result label copies the text to the clipboard for use.

\$\endgroup\$
8
\$\begingroup\$

The number one problem here is that you concatenate translated letters on to your string one at a time. Since strings are immutable in .NET (and most right thinking languages), this means for the first translated character your program allocates space for a new string of length 1 (copying the previous 0-char string), for the second character it allocates space for a new string of length 2 (copying the previous 1-char string), for the third character it allocates space for a new string of length 3 (copying the previous 2-char string), and so on. The end result is that for an input n characters long, your program will allocate 1 + 2 + 3 + ... + n = \$O(n^2)\$ space and, similarly, perform \$O(n^2)\$ operations! A better structure is to use a .NET StringBuilder which is designed precisely for this piecemeal kind of string construction. Using a StringBuilder your program will allocate \$O(n)\$ space and perform \$O(n)\$ operations -- that's a big saving when your input is of any non-trivial length.

\$\endgroup\$
4
\$\begingroup\$

One of the problems with your approach, is it's not very extensible. If you wanted different rotation factors or even to make a full Caesar Cypher, you would have to totally rewrite your code. A math based approach(Mod 26) can be used to allow any rotation factor, within reasonable limits.

Another approach which will allow O(n) space is to convert the string to a char array and change the characters in place.

It could look something like this:

Public Function ROT13(input As String) As String
    Dim chars = input.ToArray()
    Const UpperA As Integer = Asc("A"c)
    Const LowerA As Integer = Asc("a"c)
    For i = 0 To chars.Length - 1
        If Char.IsLetter(chars(i)) Then
            If Char.IsUpper(chars(i)) Then
                chars(i) = Chr((((Asc(chars(i)) - UpperA) + 13) Mod 26) + UpperA)
            Else
                chars(i) = Chr((((Asc(chars(i)) - LowerA) + 13) Mod 26) + LowerA)
            End If
        End If
    Next
    Return New String(chars)
End Function

I've hard coded the rotation factor to 13. But it should be a simple matter to add a rotation parameter to the function.

\$\endgroup\$
  • 1
    \$\begingroup\$ On the other hand, the current case-based version is quite clear in what it's doing. \$\endgroup\$ – Mark Jul 17 at 20:15
  • \$\begingroup\$ @Mark - Clear yes. But extending it to other rotations requires a total rewrite. It's always to good practice to think in terms of being able to re-use an algorithms. \$\endgroup\$ – tinstaafl Jul 17 at 20:21
  • 1
    \$\begingroup\$ It's also good practice to think in terms of maintenance, and a ROT-13 function is more likely to need maintenance than to need to be turned into a Caesar cipher. \$\endgroup\$ – Mark Jul 17 at 20:23
  • \$\begingroup\$ Surely a single modulo expression is far more readable and maintainable than something containing branching logic! \$\endgroup\$ – Daniel McLaury Jul 17 at 21:07
  • \$\begingroup\$ @DanielMcLaury: Maintainable and extensible - yes; readable - not necessarily. \$\endgroup\$ – AJD Jul 18 at 22:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.