;------------------------------------------------------------------------------------------------------------------------------------------ #DefineFunction udfBaseConvert (strNumFrom, intBaseFrom, intBaseTo) ; If any parameter contains invalid data, then return empty string. If strNumFrom == "" || intBaseFrom > 36 || intBaseFrom < 2 || intBaseTo > 36 || intBaseTo < 2 Then Return "" strNumFrom = StrUpper (strNumFrom) If StrClean (strNumFrom, StrSub ("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1, intBaseFrom), "", @TRUE, 1) != "" Then Return "" arrTemp = ArrayFromStr (strNumFrom) intElemsFrom = ArrInfo (arrTemp, 1) intElemFromLast = intElemsFrom - 1 arrFrom = ArrDimension (intElemsFrom) For intElem = 0 To intElemFromLast ; Decode characters to integer values and reverse direction. arrTemp[intElem] = Char2Num (arrTemp[intElem]) - 48 arrFrom[intElemFromLast - intElem] = arrTemp[intElem] - 7 * (arrTemp[intElem] > 9) Next Drop (arrTemp) intElemsTo = Int (1 + (intElemsFrom * Log10 (intBaseFrom) / Log10 (intBaseTo))) ; How many digits to expect? intElemToLast = intElemsTo - 1 arrCum = ArrDimension (intElemsTo) arrTo = ArrDimension (intElemsTo) ArrInitialize (arrCum, 0) ArrInitialize (arrTo, 0) arrTo[0] = 1 For intElemFrom = 0 To intElemFromLast ; For each input digit. For intElemTo = 0 To intElemToLast ; Add the input digit times ToBase to the cumulator. arrCum[intElemTo] = arrCum[intElemTo] + (arrTo[intElemTo] * arrFrom[intElemFrom]) If arrCum[intElemTo] == 0 Then Continue intTemp = arrCum[intElemTo] intRemainder = 0 intPow = intElemTo While intTemp >= intBaseTo ; Fix up any remainders in ToBase. intRemainder = intTemp / intBaseTo arrCum[intPow] = intTemp - intRemainder * intBaseTo intPow = intPow + 1 arrCum[intPow] = arrCum[intPow] + intRemainder intTemp = arrCum[intPow] EndWhile Next ; Calculate the next power in ToBase format. For intElemTo = 0 To intElemToLast arrTo[intElemTo] = arrTo[intElemTo] * intBaseFrom Next For intElemTo = 0 To intElemToLast ; Check for any remainders. If arrTo[intElemTo] == 0 Then Continue intTemp = arrTo[intElemTo] intRemainder = 0 intPow = intElemTo While intTemp >= intBaseTo ; Fix up any remainders. intRemainder = intTemp / intBaseTo arrTo[intPow] = intTemp - intRemainder * intBaseTo intPow = intPow + 1 arrTo[intPow] = arrTo[intPow] + intRemainder intTemp = arrTo[intPow] EndWhile Next Next strNumTo = "" While arrCum[intElemToLast] == 0 ; Skip leading zeroes. intElemToLast = intElemToLast - 1 EndWhile For intElemTo = intElemToLast To 0 By -1 ; Encode integer values to characters and reverse direction. strNumTo = strNumTo : Num2Char (arrCum[intElemTo] + 48 + 7 * (arrCum[intElemTo] > 9)) Next Drop (arrTo, arrCum, arrFrom) Return strNumTo ;.......................................................................................................................................... ; This UDF "udfBaseConvert" converts a given number string from one number base to another number base. ; Valid number bases are Base 2 to Base 36. ; The number string can be of any length. ; ; Parameters: ; strNumFrom ... String of numbers and/or valid letters. Letters can be in upper or lower case. ; intBaseFrom ... Integer number (2..36), the number base of the given number string. ; intBaseTo ... Integer number (2..36), the number base to convert the given number string into. ; ; Return value: ; strNumTo ... String of numbers and/or valid letters. Letters are in upper case. ; On parameter failure the return value is an empty string. ;.......................................................................................................................................... ; The basic algorithm has been adapted from article ; "Base Conversion of Very Long Positive Integers", Andrew Jonkers, 20061019, Australia. ; http://www.codeproject.com/KB/recipes/BaseConverter.aspx ; ; Because of the many loops, the algorithm is a bit slow on large numbers, when interpreted in WinBatch language. ;.......................................................................................................................................... ; (c)Detlev Dalitz.20100911. ;.......................................................................................................................................... #EndFunction ;------------------------------------------------------------------------------------------------------------------------------------------ ; Test. ; Prepare Test Data. strCSV = '"NumFrom","BaseFrom","BaseTo","NumTo","Comment"' strCSV = strCSV : @CRLF : '"221",10,16,"DD",""' strCSV = strCSV : @CRLF : '"CAFE",16,10,"51966",""' strCSV = strCSV : @CRLF : '"CaFe",16,10,"51966",""' strCSV = strCSV : @CRLF : '"11001011011001110111001000111001000010000",2,36,"MANYBITS",""' strCSV = strCSV : @CRLF : '"1IAHEB54638829348494387383AD12",19,7,"136615251021020315364261540624105412221316016",""' strCSV = strCSV : @CRLF : '"GHI",16,10,"","Invalid NumFrom in relation to BaseFrom."' strCSV = strCSV : @CRLF : '"123",1,10,"","Invalid BaseFrom."' strCSV = strCSV : @CRLF : '"123",10,37,"","Invalid BaseTo."' ; Write test data to temp file. strFileTemp = FileCreateTemp ("WBT") intBytesWritten = FilePut (strFileTemp, strCSV) Drop (strCSV) ; Read test data into array. arrTest = ArrayFileGetCSV (strFileTemp, 0) intTestLast = ArrInfo (arrTest, 1) - 1 intTestFirst = 1 ; Skip header line. ; Do the test loop. For intT = intTestFirst To intTestLast strNumTo = udfBaseConvert (arrTest[intT, 0], arrTest[intT, 1], arrTest[intT, 2]) ; Prepare message output. If arrTest[intT, 4] != "" strComment = arrTest[intT, 4] ; Use comment from CSV file if any. Else ; Compare UDF result with given NumTo value from CSV file. strComment = "UDF result is invalid." If strNumTo == arrTest[intT, 3] Then strComment = "UDF result is valid." EndIf strMsgTitle = "Test " : intT : " of " : intTestLast : "|udfBaseConvert (strNumFrom, intBaseFrom, intBaseTo)" strMsgText = "From Number (Base " : arrTest[intT, 1] : "): " : @LF : arrTest[intT, 0] strMsgText = strMsgText : @LF : "To Number (Base " : arrTest[intT, 2] : "): " : @LF : strNumTo strMsgText = strMsgText : @LF : @LF : "Comment: " : @LF : strComment Pause (strMsgTitle, strMsgText) Next :CANCEL If FileExist (strFileTemp) == 1 Then blnResult = FileDelete (strFileTemp) Exit