p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   BOOK: Stephens' Visual Basic Programming 24-Hour Trainer (http://p2p.wrox.com/forumdisplay.php?f=621)
-   -   Converting Roman numerals (http://p2p.wrox.com/showthread.php?t=98817)

 Maximilian April 21st, 2016 03:50 PM

Converting Roman numerals

Hello everybody,

I have started learning VB and am reading Stephens' Visual Basic Programming 24-Hour Trainer, which I find very systematic and helpful, but I cannot wait until I finish the book to write programs, so I am dabbling in some simple challenges while I read. I want to write a program that would convert Roman numerals to Arabic ones. I am sure this code already exists on the Web, but I would like to write my own as an exercise.

I think the Roman numeral would be a String input, which we would have to convert to an array of letters, then parse the array, pull out the special combinations IV, IX, XL, XC, CD and CM and convert them to their respective integers, then convert the remaining letters to integers, and add all the integers together to get the answer.

My question is, what would be the best command syntax to isolate the special combinations and to loop through the array to convert the letters into integers? I would be very grateful for any pointers. Thank you very much for your help.

All the best,
Maximilian

 Rod Stephens April 22nd, 2016 10:37 AM

Hi Maximilian,

I'm glad you're enjoying the book. Tell your friends and coworkers!

You're exactly right about getting practice. That's the best way to learn to program, and I wouldn't wait until I'd finished the book. It;s best to experiment with things as you learn them.

This sounds like a good project to work on. I think you can just loop through the letters from right-to-left (with a for loop). Start with a total variable initialized to 0. then when you reach a letter, there are two cases:
1. If the new letter's value is greater than the value of the letter before it (to the right), then it's a case like IV. In that case subtract the letter's value from a total.
2. If the new letter's value is not greater than the value of the previous letter, then it's a case like III. In that case add the letter's value to the total.
For example, with XIV you would add the values like this: +5, -1, +10 to get the final value 14.

Let me know if you get stuck.

Rod

 Rod Stephens April 22nd, 2016 11:18 AM

Oh, yeah. This technique doesn't detect badly formed Roman numerals like IXIV, which isn't allowed. (It should be XIII.) For bonus points see if you can figure out how to make the program detect that kind of mistake. [:)]

Rod

 Maximilian April 25th, 2016 09:44 AM

Dr. Stephens, thank you very much for your guidance. Unfortunately, you are giving too much credit to my current programming abilities. I was able to cobble together a program that actually runs, but its functionality at this stage is very limited, as follows:

Code:

```Public Class Form1     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load         Dim RomInp As String 'User input         Dim RomNum As Integer = 0 'Final answer         Dim RomNumEl As String 'Each letter in user input         Dim RomNumElNum As Integer 'Each letter in user input converted to its numeric value         Dim Prompt1 As String = "Enter a Roman numeral in capitals"         Dim ErrMess1 As String = "Please enter a valid Roman numeral!" Main:         RomInp = InputBox(Prompt1, "Roman numeral")         If Not RomInp.Contains("I") And Not RomInp.Contains("V") And Not RomInp.Contains("X") And Not RomInp.Contains("L") And Not RomInp.Contains("C") And Not RomInp.Contains("D") And Not RomInp.Contains("M") Then             MsgBox(ErrMess1)             GoTo Main 'Reject invalid input from user         End If         For Each i In RomInp             RomNumEl = Microsoft.VisualBasic.Right(RomInp, 1)             If RomNumEl = "I" Then                 RomNumElNum = 1             ElseIf RomNumEl = "V" Then                 RomNumElNum = 5             ElseIf RomNumEl = "X" Then                 RomNumElNum = 10             ElseIf RomNumEl = "L" Then                 RomNumElNum = 50             ElseIf RomNumEl = "C" Then                 RomNumElNum = 100             ElseIf RomNumEl = "D" Then                 RomNumElNum = 500             ElseIf RomNumEl = "M" Then                 RomNumElNum = 1000             End If             RomNum += RomNumElNum         Next i         MsgBox(RomNum, , "Arabic equivalent")     End Sub End Class```
For single letters or series of the same type of letter it gives correct answers, such as "3" for "III," but it gets confused if there is a combination of different letters. For example, it answers "4" for "XIII," "10" for "XV" and "300" for "MDC," I don't know why.

I tried adding a line for subtraction of a smaller number from the whole, but cannot get that version to run at all. So, when I add at the end of the loop:

Code:

```If i + 1 < i Then                 RomNum -= RomNumElNum             Else                 RomNum += RomNumElNum             End If         Next i```
the program does not compile anymore, and I get a message "Operator '+' is not defined for types 'Char' and 'Integer'." I think I'm not using correct syntax for the loop. Is there any way you could tell me how to fix it?

Thank you very much for your kind help.

Best regards,
Maximilian

 Rod Stephens April 25th, 2016 12:10 PM

Hi Maximillian,

It looks like you're on the right track. There are a few things I can see off hand. For example, you're big If Then statement you check that the input contains at least one of I, X, V, etc. But it doesn't ensure that it doesn't contain anything else like Q. Not a huge deal.

The way the program is structured now, you need an infinite loop in Form_Load. It's easier if you use a TextBox instead of an InputBox. Then you can run the code in a Button instead of Form_Load.

The long If Then ElseIf series is a good way to examine the input letters. You could add an Else at the very end to display an error if the input contains a Q or % or something.

If you attach your program, I'll take a look. To do that:
1. Close Visual Studio and then delete the bin, obj, and .vs directories
2. Move up a directory level so you're above the project's main directory. Right-click it and select "Send To > Compressed (zipped) folder"
4. Look below in the Additional Options section, click Manage Attachments, and attach the zip file.
I should be able to figure out what's going on. (Also let me know what version of Visual Studio you're using so I can use the right version for you.)

 Maximilian April 25th, 2016 01:00 PM

Hi Dr. Stephens,

As for the big If...Then statement in the beginning, I can assure you that it does reject all the Qs, %s, lower case letters, Arabic numbers, decimal points, etc., because I have tested that. It's just that the meat of the program is not written properly [:confused:].

I am using Microsoft Visual Studio Community 2015, Version 14.0.25123.00, Update 2. I have removed bin and obj (there was no .vs folder or file) and made a zipped folder as you directed. Unfortunately, I don't seem to have an option to post attachments on this forum, and I see at the bottom of the page "You may not post attachments." Did they make me into some kind of a limited user? If I can't attach the folder, maybe you can copy the code and paste it into a new project in your Visual Studio? I am sorry for the trouble and thank you very much for your help.

 Rod Stephens April 25th, 2016 02:49 PM

1 Attachment(s)
Quote:
 Then statement in the beginning, I can assure you that it does reject all the Qs, %s, lower case letters, Arabic numbers, decimal points, etc., because I have tested that. It's just that the meat of the program is not written properly [:confused:].
Sorry, I mean you could fool it if the input contains one of the allowed letters in addition to prohibited letters. For example, try IQ. The I makes it pass the If test and then the Q doesn't make sense.

> "You may not post attachments."

Huh. I don't know why that's the case. Maybe if you click Advanced Options? (And actually I should have been less lazy. It's just one method so I could have copied and pasted it into a new program easily enough.)

I think VS 2015 creates the .vs directory, but it may be hidden in Windows Explorer (or File Explorer as they're calling it these days). But the issue is moot if you can't post an attachment.

Another tip: Most programmers try hard to avoid using GoTo because it makes the code harder to understand.

I've attached an example that seems to work if the input is well-formed. For example, it doesn't complain about values like XIVI, XVVV, and IXIV, which should not be allowed. You can try to figure out how to catch cases like those. [;)]

Give it a try and let me know if you get stuck. (I actually haven't thought it through yet. For this sort of thing, it's important to be sure you understand what should happen and why before you start writing code, and I haven't done that.)

 Maximilian April 25th, 2016 04:47 PM

Dr. Stephens, I have run your program in Visual Studio, and it looks and works so beautifully, it makes me want to cry, not least because I don't know most of the functions in it. I have to keep reading the book!

Just for my education, if I may ask two very basic questions, how can it be that the variable "last_letter" is first defined merely as

Code:

`Dim last_letter As Integer = 0`
and is next used for numeric comparison with a much more specifically defined "new_letter":

Code:

`If (new_letter < last_letter) Then`
?

Just where did we tell the program that "last_letter" is the previous numeric value in the string?

Second, I think you are using "Return" function instead of my "GoTo." To which point in the code exactly does it return?

As always, thank you very much for the instruction!

 Rod Stephens April 25th, 2016 05:51 PM

Good questions.

Quote:
 Just where did we tell the program that "last_letter" is the previous numeric value in the string?
The code first sets last_letter to 0, which is smaller than any value that a Roman numeral letter can have. That means when we look at the first letter on the right, last_letter will always be smaller so we add.

After the tests, we set last_letter = new_letter so we remember what the most recent letter was during the next trip through the loop.

Quote:
 Second, I think you are using "Return" function instead of my "GoTo." To which point in the code exactly does it return?
The way modern event-driven programs work is that they display a user interface and then just sit there waiting for the user to do something. When you click the button, it's Click event handler springs into action so do something, in this example performing the Roman-to-Arabic calculation.

When the event handler exits, control goes back to the main event processing code, which is handled automatically for you, and the program sits around waiting for you to do something again such as clicking the button.

The Return statement tells the event handler to just exit early. Control returns to the event processing code as if the event handler had ended normally.

(PS - This sort of thing isn't hard, but it does take practice.)

 All times are GMT -4. The time now is 09:55 PM.