|
|
![]() |
|
||
|
|
|||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||
| Visual Basic Helper Routines Pure VB: Converting Numbers to Roman Numerals (and Back) |
||
| Posted: | Monday March 25, 2002 | |
| Updated: | Monday December 26, 2011 | |
| Applies to: | VB4-32, VB5, VB6 | |
| Developed with: | VB6, Windows XP | |
| OS restrictions: | None | |
| Author: | Ian Williams | |
|
Related: |
Pure VB: Converting Numbers to Fractions Pure VB: Converting Numbers to Roman Numerals (and Back) Pure VB: Implementing a Number-To-Text Conversion Function |
|
| Prerequisites |
| None. |
|
|
Although
not as popular as the request for a routine to convert a numeric value
into a textual representation, conversion to Roman Numerals still
receives considerable interest. This method, posted by Ian Williams in
September 2001 to the comp.lang.vb.* newsgroup demonstrates the conversion
of Arabic values both to and from Roman Numerals.The number-to-roman method is straightforward. The numeric value is dissected into its constituent ones, tens, hundreds and thousands, then uses VB's String function to create a string representing the constituent values. Where a value borders a Roman Numeral transition point, additional checks are made to determine whether the value is only one more or less than the transition point, and the appropriate two-letter code is added. In the roman-to-number routine, the Roman string is converted into a tokenized string, then each token is compared with adjacent tokens to determine the next total value of similar tokens. The result is multiplied by the token value and assigned to a temp variable, which in turn is assigned to the function result. I have made a couple of changes to the author's original routine to improve reading as an HTML page. |
| BAS Module Code |
| None. |
|
|
| Form Code |
|
|
| To a form add a listbox (List1) and a command button (Command1) along with the following: |
|
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long
Private Const LB_SETTABSTOPS As Long = &H192
Private Sub Form_Load()
ReDim TabArray(0 To 1) As Long
TabArray(0) = 41
TabArray(1) = 103
'set list tabstops
Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 0&, ByVal 0&)
Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 2&, TabArray(0))
Randomize Time
Command1.Caption = "Convert Values"
End Sub
Private Sub Command1_Click()
Dim vArabic As Long
Dim sRoman As String
Dim vArabicBack As Long
List1.Clear
'create 20 random Arabic and Roman values
Do
'create a random number
vArabic = Int(Rnd(1) * 2002) + 1
'create Roman Numeral from the value
sRoman = NumberToRoman(vArabic)
'recreate Arabic value from the Roman
vArabicBack = RomanToNumber(sRoman)
'display the three in the list
List1.AddItem vArabic & vbTab & _
sRoman & vbTab & _
vArabicBack
Loop Until List1.ListCount = 20
End Sub
Private Function NumberToRoman(nArabicValue As Long) As String
Dim nThousands As Long
Dim nFiveHundreds As Long
Dim nHundreds As Long
Dim nFifties As Long
Dim nTens As Long
Dim nFives As Long
Dim nOnes As Long
Dim tmp As String
'take the value passed and split it out
'to values representing the number of
'ones, tens, hundreds, etc
nOnes = nArabicValue
nThousands = nOnes \ 1000
nOnes = nOnes - nThousands * 1000
nFiveHundreds = nOnes \ 500
nOnes = nOnes - nFiveHundreds * 500
nHundreds = nOnes \ 100
nOnes = nOnes - nHundreds * 100
nFifties = nOnes \ 50
nOnes = nOnes - nFifties * 50
nTens = nOnes \ 10
nOnes = nOnes - nTens * 10
nFives = nOnes \ 5
nOnes = nOnes - nFives * 5
'using VB's String function, create
'a series of strings representing
'the number of each respective denomination
tmp = String(nThousands, "M")
'handle those cases where the denominator
'value is on either side of a roman numeral
If nHundreds = 4 Then
If nFiveHundreds = 1 Then
tmp = tmp & "CM"
Else
tmp = tmp & "CD"
End If
Else
'not a 4, so create the string
tmp = tmp & String(nFiveHundreds, "D") & String(nHundreds, "C")
End If
If nTens = 4 Then
If nFifties = 1 Then
tmp = tmp & "XC"
Else
tmp = tmp & "XL"
End If
Else
tmp = tmp & String(nFifties, "L") & String(nTens, "X")
End If
If nOnes = 4 Then
If nFives = 1 Then
tmp = tmp & "IX"
Else
tmp = tmp & "IV"
End If
Else
tmp = tmp & String(nFives, "V") & String(nOnes, "I")
End If
NumberToRoman = tmp
End Function
Private Function RomanToNumber(ByVal strRoman As String) As Long
Dim cnt As Long
Dim strLen As Long
Dim nChar As Long
Dim nNextChar As Long
Dim nNextChar2 As Long
Dim tmpVal As Long
'convert to lower case, and check for
'any invalid strings
strRoman = LCase(strRoman)
If InStr(strRoman, "iiii") Or _
InStr(strRoman, "xxxx") Or _
InStr(strRoman, "cccc") Or _
InStr(strRoman, "vv") Or _
InStr(strRoman, "ll") Or _
InStr(strRoman, "dd") Then
'something's fishy, so bail
RomanToNumber = -1
Exit Function
End If
'for each character in the roman numeral,
'tokenize the character by changing it
'to a numeric representation. For example,
'the Roman Numeral 1995 (MCMXCV) is
'represented by the tokenized string
'"757352"
strLen = Len(strRoman)
For cnt = 1 To strLen
Select Case Mid$(strRoman, cnt, 1)
Case "i": Mid$(strRoman, cnt, 1) = 1
Case "v": Mid$(strRoman, cnt, 1) = 2
Case "x": Mid$(strRoman, cnt, 1) = 3
Case "l": Mid$(strRoman, cnt, 1) = 4
Case "c": Mid$(strRoman, cnt, 1) = 5
Case "d": Mid$(strRoman, cnt, 1) = 6
Case "m": Mid$(strRoman, cnt, 1) = 7
End Select
Next
For cnt = 1 To strLen
'obtain the token for the current character
nChar = CInt(Mid$(strRoman, cnt, 1))
'in order to properly sum the tokens,
'the next two tokens are also needed
If cnt < strLen Then
nNextChar = CInt(Mid$(strRoman, cnt + 1, 1))
If cnt < strLen - 1 Then
nNextChar2 = CInt(Mid$(strRoman, cnt + 2, 1))
Else
nNextChar2 = 0
End If
'based on the retrieved token value,
'calculate a temp value based on it
'and the subsequent tokens
Select Case nChar
Case 7: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 1000)
Case 6: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 500)
Case 5: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 100)
Case 4: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 50)
Case 3: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 10)
Case 2: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 5)
Case 1: tmpVal = GetTmpVal2(nChar, _
nNextChar, _
nNextChar2, _
tmpVal, _
cnt, 1)
End Select
Else
tmpVal = tmpVal + ConvertValue(nChar)
End If
If tmpVal = -1 Then Exit For
Next
RomanToNumber = tmpVal
End Function
Private Function GetTmpVal2(nChar As Long, _
nNextChar As Long, _
nNextChar1 As Long, _
tmpVal As Long, _
cnt As Long, _
intValue As Long) As Long
If nNextChar > nChar Then
If ((nNextChar - nChar = 1 And _
(nChar <> 2 And nChar <> 6)) _
Or (nNextChar - nChar = 2 And _
(nNextChar <> 4 And nNextChar <> 6))) _
And nNextChar1 < nNextChar _
And nNextChar1 <> nChar Then
tmpVal = tmpVal + ConvertValue(nNextChar) - intValue
cnt = cnt + 1
Else
tmpVal = -1
End If
Else
tmpVal = tmpVal + intValue
End If
GetTmpVal2 = tmpVal
End Function
Private Function ConvertValue(ByVal nVal As Long) As Long
Select Case nVal
Case 7: ConvertValue = 1000
Case 6: ConvertValue = 500
Case 5: ConvertValue = 100
Case 4: ConvertValue = 50
Case 3: ConvertValue = 10
Case 2: ConvertValue = 5
Case 1: ConvertValue = 1
End Select
End Function |
| Comments |
|
|
|
|
|
|||||
|
|||||
|
|
|||||
|
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |
![]() |