How to nest multiple IF statements in Visual Basic 6? - vb6

How can I use an if in another if in Visual Basic 6?
For example, in C++ I can start my statements with { and finish them with }, and I can use another if in the first statement.
For example:
if m>3
{ .....
if a>5
{
......
}
else {....}
} else ........
… but in Visual Basic there is no { } or something similar it
i want to writ a program that recive a time from user and Reduce 4:30 from it ! for example when user runs it , it asks : what time is it in Tehran ? and user enter time (for example 16:30) and then program Reduces 4 hour and 30 minutes from it ! and print : GMT time is : 12:00 ! i'll updat my post and put my code ! please read it !
Option Explicit
Private Sub Command1_Click()
Cls
Dim h As Integer, m As Integer, hm As Integer, mm As Integer, t As Integer
Dim fh As String, fm As String, fhm As String, fmm As String
t = InputBox("Enter time")
h = t \ 100
m = t Mod 100
Select Case h
Case 0 To 24
If m < 60 Then
If m >= 30 Then
hm = h - 4
mm = m - 30
If h < 10 Then fh = Format(h, String(2, "0")) Else fh = h
If m < 10 Then fm = Format(m, String(2, "0")) Else fm = m
If hm < 10 Then fhm = Format(hm, String(2, "0")) Else fhm = hm
If mm < 10 Then fmm = Format(mm, String(2, "0")) Else fmm = mm
Print
Print " Tehran Time is : "; fh; ":"; fm
Print
Print " GMT Time is : "; fhm; ":";
Else
hm = h - 5
mm = m + 30
If h < 10 Then fh = Format(h, String(2, "0")) Else fh = h
If m < 10 Then fm = Format(m, String(2, "0")) Else fm = m
If hm < 10 Then fhm = Format(hm, String(2, "0")) Else fhm = hm
If mm < 10 Then fmm = Format(mm, String(2, "0")) Else fmm = mm
Print
Print " Tehran Time is : "; fh; ":"; fm
Print
Print " GMT Time is : "; fhm; ":"; fmm
End If
End If
Case Else
Beep
Print
Print " Time is wrong !!! Try again "
End Select
End Sub
Private Sub Command2_Click()
End
End Sub
Private Sub Form_Load()
End Sub

If clauses in VB are ended with "End If" (case insensitive). No brackets whatsoever.
You may nest as many if clauses as you want, as long as you close them:
If ... Then
*Do stuff*
If ... Then
*Do more stuff*
End If
End If

Single-line If statements can also be nested:
If (a) Then [a_stuff] : If (b) Then [a_and_b_stuff] Else [a_and_notb_stuff] Else [nota_stuff]
Note that no more [a_stuff] can appear after [a_and_notb_stuff], since there's no way to tell where b's Else-statements end, so nothing can appear in a clause after a nested If statement.
Any of the *_stuff parts can be empty. But you may have some difficulty with an empty [a_and_notb_stuff], since the VB6 IDE seems to be a bit temperamental here, and will try inserting an invalid third 'Else' statement there. To work around this you can put a ':' in place of [a_and_notb_stuff]. The colon will be removed by the IDE, but it won't then insert another Else statement.
Addendum: I should point out that this whole post should be treated as information, and not as a recommendation. Nesting single-line If statements like this makes for very unreadable and bug-prone code.

Related

Date Year in the Past vbScript [duplicate]

I am trying to condition a time read as a string lies between a specified time interval using VBScript. Following is the script:
dim splitString, currentTime
splitString = Split("12 59 00")
currentTime = TimeSerial(splitString(0),splitString(1), splitString(2))
If ((DateAdd("n",-1,time())) <= currentTime < DateAdd("n", 1,time())) Then
Wscript.Echo currentTime
End If
This does not seem to work. Getting an echo even if the current time is outside the time interval.
In Python you can check 'is in an interval' using the short
if x <= y < z:
...
but in VBScript you need the longer
If x <= y And y < z Then
...
You need to evaluate both conditions independently.
dim splitString, currentTime
splitString = Split("3 39 00")
currentTime = TimeSerial(splitString(0),splitString(1), splitString(2))
If (DateAdd("n",-1,time()) <= currentTime) And (currentTime < DateAdd("n", 1,time())) Then
Wscript.Echo currentTime
End If
I used DateDiff. Modified the IF statement to:
If (DateDiff("n",DateAdd("n",-1,time()),currentTime) = 1 AND DateDiff("n",currentTime,DateAdd("n",1,time())) = 1) Then
Wscript.Echo currentTime
End If
Worked as expected.

R - Using a While() loop inside a FOR() loop

I am rebuilding a VBA code inside R, that counts transitions from a rating to another based on different conditions:
It is as follows:
## attach the relevant data table
attach(cohort)
# define the matrices that will contain all the counting information
ni = matrix(0,nrow = 1, ncol = classes - 1)
nij = matrix(0, nrow = classes-1, ncol = classes+1)
for (k in 1:obs)
{
# define the year of the kth observation
t = apply(data.frame(date[k],ystart),1,max, na.rm = F)
#t = year(as.Date(t))
while (t < yend)
{
# if this observation and the second one belong to the same id and year, break and move to the next one
if (id[k] == id[k+1] & date[k] == date[k+1]) {break}
# if the rating of this observation is 0 (not rated) or in default, then leave it
if (rating[k] == classes | rating[k] == 0) {break}
# add to the group of customers with rating = rating_k, 1 observation
rating_k = rating[k]
ni[rating_k] = ni[rating_k]+1
# determine the rating from end of next year
if (id[k] != id[k+1] | date[k+1] > (t+1))
{newrat = rating_k}
else
{
kn = k +1
while (date[kn]==date[kn+1] & id[kn]==id[kn+1])
{
if (rating[kn]==classes) {break}
Kn = kn+1
}
newrat = rating[kn]
}
nij[rating_k, newrat] = (nij[rating_k, newrat] + 1)
if(newrat!=rating[k]) {break}
else
{t = (t+1)}
}
print (k)
}
At the end of my code, if the condition " if(newrat!=rating[k]) " is met, i want my code to break and move to the next K. Else, if the condition is not met, i have t = t + 1, where the code will go back to the condition inside the while(t
I added in the end "print(k)" to understand at which "for k ..." step the code stops, and it always stops at k = 9 while k = 1 to 8 are printed. In total, i have 4000 observations but only 8 are considered, though the loop never stops and R keeps running.

Count occurrences of a character in a string

Looking for the best way to do this in VB6. Typically, I would use this approach...
' count spaces
For i = 1 To Len(text)
If Mid$(text, i, 1) = " " Then count = count + 1
Next
Not saying it's the best way, but you code do:
distinctChr = " "
count = Len(text) - Len(Replace(text, distinctChr , ""))
Use the split command like this
Dim TempS As String
TempS = " This is a split test "
Dim V As Variant
V = Split(TempS, " ")
Cls
Print UBound(V) '7
V = Split(TempS, "i")
Print UBound(V) '3
V = Split(TempS, "e")
Print UBound(V) '1
You can combine it to a single line.
Print UBound(Split(TempS, "i"))
I did some crude timing on it. On a 40,000 character string with all spaces it seems to clock in at 17 milliseconds on a 2.4 GHz Intel Core 2 processor.
A function could look like this
Function CountChar(ByVal Text As String, ByVal Char As String) As Long
Dim V As Variant
V = Split(Text, Char)
CountChar = UBound(V)
End Function
I would use a modified bucket sort:
Dim i as Integer
Dim index As Integer
Dim count as Integer
Dim FoundByAscii(0 To 255) As Boolean
For i = 1 To Len(text)
index = Asc(Mid$(text, i, 1))
FoundByAscii(index) = True
Next i
count = 0
For i = 0 To 255
If FoundByAscii(i) Then
count = count + 1
End If
Next i
...and your result is in count. The performance is O(N) - if Mid$ is O(1).
Edit:
Based on your clarification, do this:
' count spaces
Dim asciiToSearchFor As Integer
asciiToSearchFor = Asc(" ")
For i = 1 To Len(text)
If Asc(Mid$(text, i, 1)) = asciiToSearchFor Then count = count + 1
Next
As ascii compares have to be faster that string comparison. I'd profile it just in case, but I'm pretty sure.
It's not clear what you mean by the best way to do this.
If you want something very fast, but totally unmaintainable, adapt this horrible code that delves into the underlying memory of a VB6 string to count the number of words. Courtesy of VBspeed.

I want a function in VB SCRIPT to calculate numerology

I want a function to calculate numerology.For example if i enter "XYZ" then my output should be 3 .
Here is how it became 3:
X = 24
Y = 25
Z = 26
on adding it becomes 75 which again adds up to 12 (7+5) which again adds up to 3(1+2) . Similarly whatever names i should pass,my output should be a single digit score.
Here you are:
Function Numerology(Str)
Dim sum, i, char
' Convert the string to upper case, so that 'X' = 'x'
Str = UCase(Str)
sum = 0
' For each character, ...
For i = 1 To Len(Str)
' Check if it's a letter and raise an exception otherwise
char = Mid(Str, i , 1)
If char < "A" Or char > "Z" Then Err.Raise 5 ' Invalid procedure call or argument
' Add the letter's index number to the sum
sum = sum + Asc(char) - 64
Next
' Calculate the result using the digital root formula (http://en.wikipedia.org/wiki/Digital_root)
Numerology = 1 + (sum - 1) Mod 9
End Function
In vbscript:
Function numerology(literal)
result = 0
for i = 1 to Len(literal)
'' // for each letter, take its ASCII value and substract 64,
'' so "A" becomes 1 and "Z" becomes 26
result = result + Asc(Mid(literal, i, 1)) - 64
next
'' // while result is bigger than 10, let's sum it's digits
while(result > 10)
partial = 0
for i = 1 to Len(CStr(result))
partial = partial + CInt(Mid(CStr(result), i, 1))
next
result = partial
wend
numerology = result
End Function
I have no idea what this could possible be used for but it was fun to write anyway.
Private Function CalcStupidNumber(ByVal s As String) As Integer
s = s.ToLower
If (s.Length = 1) Then 'End condition
Try
Return Integer.Parse(s)
Catch ex As Exception
Return 0
End Try
End If
'cover to Values
Dim x As Int32
Dim tot As Int32 = 0
For x = 0 To s.Length - 1 Step 1
Dim Val As Integer = ConvertToVal(s(x))
tot += Val
Next
Return CalcStupidNumber(tot.ToString())
End Function
Private Function ConvertToVal(ByVal c As Char) As Integer
If (Char.IsDigit(c)) Then
Return Integer.Parse(c)
End If
Return System.Convert.ToInt32(c) - 96 ' offest of a
End Function

How do I find the Excel column name that corresponds to a given integer? [duplicate]

This question already has answers here:
How to convert a column number (e.g. 127) into an Excel column (e.g. AA)
(60 answers)
Closed 9 years ago.
How would you determine the column name (e.g. "AQ" or "BH") of the nth column in Excel?
Edit: A language-agnostic algorithm to determine this is the main goal here.
I once wrote this function to perform that exact task:
public static string Column(int column)
{
column--;
if (column >= 0 && column < 26)
return ((char)('A' + column)).ToString();
else if (column > 25)
return Column(column / 26) + Column(column % 26 + 1);
else
throw new Exception("Invalid Column #" + (column + 1).ToString());
}
Here is the cleanest correct solution I could come up with (in Java, but feel free to use your favorite language):
String getNthColumnName(int n) {
String name = "";
while (n > 0) {
n--;
name = (char)('A' + n%26) + name;
n /= 26;
}
return name;
}
But please do let me know of if you find a mistake in this code, thank you.
A language agnostic algorithm would be as follows:
function getNthColumnName(int n) {
let curPower = 1
while curPower < n {
set curPower = curPower * 26
}
let result = ""
while n > 0 {
let temp = n / curPower
let result = result + char(temp)
set n = n - (curPower * temp)
set curPower = curPower / 26
}
return result
This algorithm also takes into account if Excel gets upgraded again to handle more than 16k columns. If you really wanted to go overboard, you could pass in an additional value and replace the instances of 26 with another number to accomodate alternate alphabets
Thanks, Joseph Sturtevant! Your code works perfectly - I needed it in vbscript, so figured I'd share my version:
Function ColumnLetter(ByVal intColumnNumber)
Dim sResult
intColumnNumber = intColumnNumber - 1
If (intColumnNumber >= 0 And intColumnNumber < 26) Then
sResult = Chr(65 + intColumnNumber)
ElseIf (intColumnNumber >= 26) Then
sResult = ColumnLetter(CLng(intColumnNumber \ 26)) _
& ColumnLetter(CLng(intColumnNumber Mod 26 + 1))
Else
err.Raise 8, "Column()", "Invalid Column #" & CStr(intColumnNumber + 1)
End If
ColumnLetter = sResult
End Function
Joseph's code is good but, if you don't want or need to use a VBA function, try this.
Assuming that the value of n is in cell A2
Use this function:
=MID(ADDRESS(1,A2),2,LEN(ADDRESS(1,A2))-3)
IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))
This works 2 letter columns (up until column ZZ). You'd have to nest another if statement for 3 letter columns.
The formula above fails on columns AY, AZ and each of the following nY and nZ columns. The corrected formula is:
=IF(COLUMN()>26,CHAR(ROUNDDOWN((COLUMN()-1)/26,0)+64)&CHAR(MOD((COLUMN()-1),26)+65),CHAR(COLUMN()+64)
Ruby one-liner:
def column_name_for(some_int)
some_int.to_s(26).split('').map {|c| (c.to_i(26) + 64).chr }.join # 703 => "AAA"
end
It converts the integer to base26 then splits it and does some math to convert each character from ascii. Finally joins 'em all back together. No division, modulus, or recursion.
Fun.
FROM wcm:
If you don't want to use VBA, you can use this
replace colnr with the number you want
=MID(ADDRESS(1,colnr),2,LEN(ADDRESS(1,colnr))-3)
Please be aware of the fact that this formula is volatile because of the usage of the ADDRESS function. Volatile functions are functions that are recalculated by excel after EVERY change.
Normally excel recalculates formula's only when their dependent references changes.
It could be a performance killer, to use this formula.
And here is a conversion from the VBScript version to SQL Server 2000+.
CREATE FUNCTION [dbo].[GetExcelColRef]
(
#col_seq_no int
)
RETURNS varchar(5)
AS
BEGIN
declare #Result varchar(5)
set #Result = ''
set #col_seq_no = #col_seq_no - 1
If (#col_seq_no >= 0 And #col_seq_no < 26)
BEGIN
set #Result = char(65 + #col_seq_no)
END
ELSE
BEGIN
set #Result = [dbo].[GetExcelColRef] (#col_seq_no / 26) + '' + [dbo].[GetExcelColRef] ((#col_seq_no % 26) + 1)
END
Return #Result
END
GO
This works fine in MS Excel 2003-2010. Should work for previous versions supporting the Cells(...).Address function:
For the 28th column - taking columnNumber=28; Cells(1, columnNumber).Address returns "$AB$1".
Doing a split on the $ sign returns the array: ["","AB","1"]
So Split(Cells(1, columnNumber).Address, "$")(1) gives you the column name "AB".
UPDATE:
Taken from How to convert Excel column numbers into alphabetical characters
' The following VBA function is just one way to convert column number
' values into their equivalent alphabetical characters:
Function ConvertToLetter(iCol As Integer) As String
Dim iAlpha As Integer
Dim iRemainder As Integer
iAlpha = Int(iCol / 27)
iRemainder = iCol - (iAlpha * 26)
If iAlpha > 0 Then
ConvertToLetter = Chr(iAlpha + 64)
End If
If iRemainder > 0 Then
ConvertToLetter = ConvertToLetter & Chr(iRemainder + 64)
End If
End Function
APPLIES TO: Microsoft Office Excel 2007 SE / 2002 SE / 2000 SE / 97 SE
I suppose you need VBA code:
Public Function GetColumnAddress(nCol As Integer) As String
Dim r As Range
Set r = Range("A1").Columns(nCol)
GetColumnAddress = r.Address
End Function
This does what you want in VBA
Function GetNthExcelColName(n As Integer) As String
Dim s As String
s = Cells(1, n).Address
GetNthExcelColName = Mid(s, 2, InStr(2, s, "$") - 2)
End Function
This seems to work in vb.net
Public Function Column(ByVal pColumn As Integer) As String
pColumn -= 1
If pColumn >= 0 AndAlso pColumn < 26 Then
Return ChrW(Asc("A"c) + pColumn).ToString
ElseIf (pColumn > 25) Then
Return Column(CInt(math.Floor(pColumn / 26))) + Column((pColumn Mod 26) + 1)
Else
stop
Throw New ArgumentException("Invalid column #" + (pColumn + 1).ToString)
End If
End Function
I took Joseph's and tested it to BH, then fed it 980-1000 and it looked good.
In VBA, assuming lCol is the column number:
function ColNum2Letter(lCol as long) as string
ColNum2Letter = Split(Cells(1, lCol).Address, "$")(0)
end function
All these code samples that these good people have posted look fine.
There is one thing to be aware of. Starting with Office 2007, Excel actually has up to 16,384 columns. That translates to XFD (the old max of 256 colums was IV). You will have to modify these methods somewhat to make them work for three characters.
Shouldn't be that hard...
Here's Gary Waters solution
Function ConvertNumberToColumnLetter2(ByVal colNum As Long) As String
Dim i As Long, x As Long
For i = 6 To 0 Step -1
x = (1 - 26 ^ (i + 1)) / (-25) - 1 ‘ Geometric Series formula
If colNum > x Then
ConvertNumberToColumnLetter2 = ConvertNumberToColumnLetter2 & Chr(((colNum - x - 1)\ 26 ^ i) Mod 26 + 65)
End If
Next i
End Function
via http://www.dailydoseofexcel.com/archives/2004/05/21/column-numbers-to-letters/
Considering the comment of wcm (top value = xfd), you can calculate it like this;
function IntToExcel(n: Integer); string;
begin
Result := '';
for i := 2 down to 0 do
begin
if ((n div 26^i)) > 0) or (i = 0) then
Result := Result + Char(Ord('A')+(n div (26^i)) - IIF(i>0;1;0));
n := n mod (26^i);
end;
end;
There are 26 characters in the alphabet and we have a number system just like hex or binary, just with an unusual character set (A..Z), representing positionally the powers of 26: (26^2)(26^1)(26^0).
FYI T-SQL to give the Excel column name given an ordinal (zero-based), as a single statement.
Anything below 0 or above 16,383 (max columns in Excel2010) returns NULL.
; WITH TestData AS ( -- Major change points
SELECT -1 AS FieldOrdinal
UNION ALL
SELECT 0
UNION ALL
SELECT 25
UNION ALL
SELECT 26
UNION ALL
SELECT 701
UNION ALL
SELECT 702
UNION ALL
SELECT 703
UNION ALL
SELECT 16383
UNION ALL
SELECT 16384
)
SELECT
FieldOrdinal
, CASE
WHEN FieldOrdinal < 0 THEN NULL
WHEN FieldOrdinal < 26 THEN ''
WHEN FieldOrdinal < 702 THEN CHAR (65 + FieldOrdinal / 26 - 1)
WHEN FieldOrdinal < 16384 THEN CHAR (65 + FieldOrdinal / 676 - 1)
+ CHAR (65 + (FieldOrdinal / 26) - (FieldOrdinal / 676) * 26 - 1)
ELSE NULL
END
+ CHAR (65 + FieldOrdinal % 26)
FROM TestData
ORDER BY FieldOrdinal
I currently use this, but I have a feeling that it can be optimized.
private String GetNthExcelColName(int n)
{
String firstLetter = "";
//if number is under 26, it has a single letter name
// otherwise, it is 'A' for 27-52, 'B' for 53-78, etc
if(n > 26)
{
//the Converts to double and back to int are just so Floor() can be used
Double value = Convert.ToDouble((n-1) / 26);
int firstLetterVal = Convert.ToInt32(Math.Floor(value))-1;
firstLetter = Convert.ToChar(firstLetterValue + 65).ToString();
}
//second letter repeats
int secondLetterValue = (n-1) % 26;
String secondLetter = Convert.ToChar(secondLetterValue+65).ToString();
return firstLetter + secondLetter;
}
=CHAR(64+COLUMN())

Resources