Simulate the "exit do" statement fused in vba in tcl - vba

This question is related to Breaking parent loop in tcl , but I am not able to implement the answer to my current code.
I have a proc written in VBA for Excel which uses "Exit do":
Do While i < numofentries
Debug.Print "------------------"
Debug.Print "j = " & j
Debug.Print "length | Element i"
path_beg = i
path_end = i
Length = 0
length_l = 0
length_u = 0
blnAngle = True
Do While Length < minlength
If (angles(i) < limitangle Or path_beg = i) Then
Length = Length + ElemEdgeLengths(i)
Debug.Print Length & " | " & i
path_end = i
i = i + 1
If i = numofentries Then Exit Do
Else
Debug.Print "Angle change..."
If path_end = path_beg Then
path(j - 1) = path_end
blnAngle = False
Debug.Print "1 Elm only: included to predecessor path:"
Debug.Print "path_end of path j = " & j - 1 & " changed to " & path_end
Else
path(j) = path_end
j = j + 1
blnAngle = False
Debug.Print path_end - path_beg + 1 & " Elms: own path with length " & Length
End If
Exit Do
End If
Loop
If blnAngle = True Then
length_l = Abs(Length - ElemEdgeLengths(path_end - 1) - minlength)
length_u = Abs(Length - minlength)
If length_l <= length_u Then
i = path_end
path(j) = path_end - 1
j = j + 1
Debug.Print "last Elm set to " & path_end - 1
Else
path(j) = path_end
j = j + 1
Debug.Print "last Elm is " & path_end
End If
End If
Loop
I have "translated" the sub to tcl like this, but I am not able to simulate the behaviour of ExitDo correctly. How can I recode the VBA Sub in Tcl correctly ? :
proc magictrap {code body} {
if {$code <= 4} {error "bad magic code"}; # Lower values reserved for Tcl
if {[catch {uplevel 1 $body} msg opt] == $code} return
return -options $opt $msg
}
proc magicthrow code {return -code $code "doesn't matter what this is"}
proc pathfinder {ElemEdgeLengths minlength LimitAngle angles} {
set j 0
set i 0
set numofentries [llength $ElemEdgeLengths]
while { $i < $numofentries } {
set path_beg $i
set path_end $i
set length 0
set length_l 0
set length_u 0
set blnAngle 1
while { ( $length < $minlength ) } {
if { ( [lindex $angles $i] < $LimitAngle ) || ( $path_beg == $i ) } {
set length [ expr { $length + [lindex $ElemEdgeLengths $i] } ]
set path_end $i
incr i
if { $i == $numofentries } { magicthrow 5 }
} else {
if { $path_end == $path_beg } {
set k [expr { $j - 1 }]
set path($k) $path_end
set blnAngle 0
} else {
set path($j) $path_end
incr j
set blnAngle 0
}
set length inf
}
}
if { $blnAngle == 1 } {
set length_l [ expr { abs( $length - [lindex $ElemEdgeLengths [expr {$path_end - 1} ] ] - $minlength ) } ]
set length_u [ expr { abs( $length - $minlength ) } ]
}
if { $length_l <= $length_u } {
set i $path_end
set path($j) [expr {$path_end - 1}]
incr j
} else {
set path($j) $path_end
incr j
}
}
return $path
}

"break" exits the innermost loop.
you could set a boolean variable at the "exit do" location:
set blnBreak 1
break
just outside the loop you will have to test it:
if { $blnBreak == 1 } {
break
}

The VB Exit Do corresponds very closely to break in Tcl (and many other languages besides).

Related

i want to use Regex.IsMatch to find TB, GB, MB in VB.net Visual Basic

I have a textbox which i need to validate for the below entries and also need to replace
"3 GB" valid input
"3.2 GB" valid input
"3.2GB" valid input >> then replace as "3.2 GB"
"3.2" invalid input, ask for follow correct format MsgBox("follow the format like: 1 TB or 1.1 TB, 1 GB, 10 MB")
"VGGGB" invalid input, ask for follow correct format MsgBox("follow the format like: 1 TB or 1.1 TB, 1 GB, 10 MB")
Sub Main()
Dim input = Console.ReadLine().ToUpper()
Dim nInput, value
Dim ChkDecimal As Double
If input IsNot "" Then
If input.EndsWith("TB") Then
nInput = input.Replace("TB", "")
If nInput IsNot vbNullString And IsNumeric(nInput) Then
value = Convert.ToDouble(nInput)
value = CDbl(value * 1048576 + 1)
ChkDecimal = FormatNumber(CDbl(value / 1048576), 2) Mod 1 ' check the number has a valid Decimal value
If ChkDecimal = 0 Then
Console.WriteLine(FormatNumber(CDbl(value / 1048576), 0) & " TB")
Else
Console.WriteLine(FormatNumber(CDbl(value / 1048576), 2) & " TB")
End If
Else
Console.WriteLine("Invalid format!! should like: 99.99 MB/GB/TB")
End If
ElseIf (input.EndsWith("GB")) Then
nInput = input.Replace("GB", "")
If nInput IsNot vbNullString And IsNumeric(nInput) Then
value = Convert.ToDouble(nInput)
value = CDbl(value * 1024)
ChkDecimal = FormatNumber(CDbl(value / 1024), 2) Mod 1 ' check the number has a valid Decimal value
If ChkDecimal = 0 Then
Console.WriteLine(FormatNumber(CDbl(value / 1024), 0) & " GB")
Else
Console.WriteLine(FormatNumber(CDbl(value / 1024), 2) & " GB")
End If
Else
Console.WriteLine("Invalid format!! should like: 99.99 MB/GB/TB")
End If
ElseIf input.EndsWith("MB") = True Then
nInput = input.Replace("MB", "")
If nInput IsNot vbNullString And IsNumeric(nInput) Then
value = Convert.ToDouble(nInput)
value = CDbl(value * 1)
Console.WriteLine(FormatNumber(CDbl(value * 1), 0) & " MB")
Else
Console.WriteLine("Invalid format!! should like: 99.99 MB/GB/TB")
End If
Else
Console.WriteLine("Invalid format!! should like: 99.99 MB/GB/TB")
End If
Else
Console.WriteLine("Capacity input Format: 99.99 MB/GB/TB")
End If
End Sub
I wouldn't use a regular-expression for this, because there's a much simpler (and more robust!) approach described below.
If you do use a regular-expression, you'll need to add all of the unit names to the expression, which is painful. Regular-expressions are not well-suited to accepting a large list of possible literal inputs.
Using a regular-expression would also mean the input would not be culture-aware, which is bad for usability (as many places around the world swap the , and . glyphs in numbers) - and you really don't want to handle things like digit-grouping, etc.
Instead, first extract and validate the unit name, then parse the numeric value using Decimal.TryParse
Like so (using C# because it's 2am here and I'm not getting paid to write this answer):
void Example()
{
String textBoxValue = "3 GB";
if( TryParseBinaryDataQuantity( textBoxValue, out Int64 valueBytes ) )
{
MessageBox.Show( "Visual Basic is dead." );
}
else
{
MessageBox.Show( "Input is not a valid binary data quantity." );
}
}
public static Boolean TryParseBinaryDataQuantity( String input, out Int64 valueBytes )
{
input = ( input ?? "" ).Trim();
if( input.Length < 3 ) // input is too short to be meaningful.
{
valueBytes = default;
return false;
}
// Extract the unit-name by taking the last 3 characters of the input string and trimming any whitespace (this isn't the most robust or correct approach, but I'm feeling lazy):
String unitName = input.Substring( startIndex: input.Length - 3 );
// Validate the unit-name and get the bytes multiplier:
if( !TryParseBinaryDataUnit( unitName, out Int64 multiplier ) )
{
valueBytes = default;
return false;
}
// Consider repeating the above but for the last 2 characters of the string in order to match input like "3GB" instead of "3GiB" and "3 GB" and "3 GiB".
// Parse and multiply:
String numberPart = input.Substring( startIndex: 0, length: input.Length - 3 );
if( Decimal.TryParse( numberPart, NumberStyles.Any, CultureInfo.CurrentCulture, out Decimal quantity )
{
Decimal bytesValue = quantity * multiplier;
// Fail if the bytesValue is non-integral or negative:
if( bytesValue != Math.Floor( bytesValue ) || bytesValue < 0 )
{
valueBytes = default;
return false;
}
return (Int64)bytesValue;
}
}
private static Boolean TryParseBinaryDataUnit( String unitName, out Int64 equivalentBytes )
{
if( "GB".Equals( unitName, StringComparison.CurrentCultureCaseInsensitive ) )
{
equivalentBytes = 1024 * 1024 * 1024; // or 1000 * 1000 * 1000 depending on if you're differentiating between GiB and GB.
return true;
}
else if( "GiB".Equals( unitName, StringComparison.CurrentCultureCaseInsensitive ) )
{
equivalentBytes = 1024 * 1024 * 1024;
return true;
}
else if( "MiB".Equals( unitName, StringComparison.CurrentCultureCaseInsensitive ) )
{
equivalentBytes = 1024 * 1024;
return true;
}
else if( "MB".Equals( unitName, StringComparison.CurrentCultureCaseInsensitive ) )
{
equivalentBytes = 1024 * 1024;
return true;
}
else if( "KB".Equals( unitName, StringComparison.CurrentCultureCaseInsensitive ) )
{
equivalentBytes = 1024;
return true;
}
else if( "KB".Equals( unitName, StringComparison.CurrentCultureCaseInsensitive ) )
{
equivalentBytes = 1024;
return true;
}
else
{
equivalentBytes = default;
return false;
}
}
I will recommend you to use proper library to parse the given input. I have used one in past for doing this (https://github.com/omar/ByteSize)
Here is quick example of how you can do this. I know there must be better way to do this but this would do the job =)
var input = Console.ReadLine();
input = input.ToLower();
var reg = Regex.Match(input, "([\\d\\.]+)");
if (reg.Success && double.TryParse(reg.Groups[1].Value, out double rawSize))
{
if (input.EndsWith("tb"))
Console.WriteLine(ByteSize.FromTeraBytes(rawSize));
else if (input.EndsWith("gb"))
Console.WriteLine(ByteSize.FromGigaBytes(rawSize));
else if (input.EndsWith("mb"))
Console.WriteLine(ByteSize.FromMegaBytes(rawSize));
else if (input.EndsWith("kb"))
Console.WriteLine(ByteSize.FromKiloBytes(rawSize));
}
Input> 1234.56mb
Output> 1.23 GB
You can try my method as following:
Imports System.Text.RegularExpressions
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'1.3 GB
'1.3gb
'1gb
Console.WriteLine("Pleasen input your entry:")
Dim str As String = TextBox1.Text
Dim str1 As String = str.Substring(str.Length - 2, 2)
If str1.ToUpper = "TB" Or str1.ToUpper = "GB" Or str1.ToUpper = "MB" Then
Dim str2 As String = str.Remove(str.Length - 2)
Dim str3 As String = str.Substring(str2.Length - 1, 1)
If str3 = " " Then
Dim str4 As String = str.Remove(str.Length - 3)
If Regex.IsMatch(str4, "^\d*[.]?\d*$") Then
MsgBox("valid input")
Else
MsgBox("follow the format like: 1 TB or 1.1 TB, 1 GB, 10 MB")
Return
End If
Else
If Regex.IsMatch(str2, "^\d*[.]?\d*$") Then
TextBox1.Text = str.Insert(str.Length - 2, " ")
MsgBox("valid input")
Else
MsgBox("follow the format like: 1 TB or 1.1 TB, 1 GB, 10 MB")
Return
End If
End If
Else
MsgBox("follow the format like: 1 TB or 1.1 TB, 1 GB, 10 MB")
Return
End If
End Sub
End Class

Fingerprint Hardware ID GetHexString

I found a fingerprint class in C# here
I'm trying to convert the function below to VB .NET but I am having issues with the line that reads s+ = (char)....Any help would be appreciated.
private static string GetHexString(byte[] bt)
{
string s = string.Empty;
for (int i = 0; i < bt.Length; i++)
{
byte b = bt[i];
int n, n1, n2;
n = (int)b;
n1 = n & 15;
n2 = (n >> 4) & 15;
if (n2 > 9)
s += ((char)(n2 - 10 + (int)'A')).ToString();
else
s += n2.ToString();
if (n1 > 9)
s += ((char)(n1 - 10 + (int)'A')).ToString();
else
s += n1.ToString();
if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
}
return s;
}
Is there a better way to write this function in VB.NET?
This
s += ((char)(n1 - 10 + (int)'A')).ToString();
is the same as
s &= Chr((n1 - 10 + Asc("A")))

AutoIt - Breaking While Loop with GUICtrlCreateButton

Ok, so I'm creating an AutoIt GUI executable to automate some functions in a website. However, I cannot find a way to break the While loop that executes the function I've created using a "STOP" button I've created. Therefore, it runs indefinitely, and I cannot quit the program. In theory, it should work, but I feel I'm missing something. Any help, folks?
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <IE.au3>
Global $msg, $instructions, $AutoLevel, $NumDogsBox, $NumDogs, $IE, $i, $o
$IE = _IECreateEmbedded()
GUICreate("Automatic Dog Feeder for Criminal Case", 900, 690)
$instructions = GUICtrlCreateButton(' Instructions ', 725, 5)
GUICtrlCreateLabel("# of Dogs: ",740,40)
$NumDogsBox = GUICtrlCreateInput("", 815, 37, 25)
$AutoLevel = GUICtrlCreateButton(' Begin Auto Feed Dog ', 700, 65)
GUICtrlCreateObj($IE, 1, 100, 915, 610)
GUISetState(#SW_SHOW)
_IENavigate($IE, "http://apps.facebook.com/criminalcase")
$IE.Document.Body.Scroll = "no"
_IEAction($IE, "stop")
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $instructions
MsgBox(0,"Instructions","1.) Log in to Facebook (if not already) in the window below" & #CRLF & "2.) Clear any notifications and get to the map screen" & #CRLF & "3.) Click on the dog bowl icon on the right of the map" & #CRLF & "4.) Enter the number of dogs you have to level up" & #CRLF & "5.) Click the Begin Auto Feed Dog button at the bottom of the window")
Case $msg = $AutoLevel
$NumDogs = GUICtrlRead($NumDogsBox)
AutoDogLevel()
EndSelect
WEnd
Func AutoDogLevel()
While 1
$stop = GUICtrlCreateButton('STOP',830,65)
$i=0
While $i < $NumDogs
If $msg = $stop Then
ExitLoop
Endif
MsgBox(0,"","1xp" & $i+1)
ControlClick("[CLASS:MacromediaFlashPlayerActiveX]","","","left",1,156,651)
Sleep(2000)
If $msg = $stop Then
ExitLoop
Endif
ControlClick("[CLASS:MacromediaFlashPlayerActiveX]","","","left",1,723,524)
MsgBox(0,"","Next Dog")
Sleep(2000)
$i = $i+1
WEnd
If $msg = $stop Then
ExitLoop
Endif
While $i > 0
If $msg = $stop Then
ExitLoop
Endif
ControlClick("[CLASS:MacromediaFlashPlayerActiveX]","","","left",1,62,525)
MsgBox(0,"","Previous Dog")
If $msg = $stop Then
ExitLoop
Endif
Sleep(1000)
$i=$i-1
WEnd
If $msg = $stop Then
ExitLoop
Endif
Sleep(3000)
WEnd
EndFunc
So, now I'm stuck. Any help will be greatly appreciated.
It's not a good idea to have more than 1 message loop for a GUI. Instead of doing it like this, I suggest keeping a variable for the current state, and only implementing a single loop. You also have some very large sleeps inside the message loop as well.
I haven't tested the code, but here is the message loop re-written to use a state variable and timers instead of multiple loops and sleeps. This is a much better design that will ensure your GUI is always responsive to ALL the buttons, and I think you'll find it easier to work with as well once you get used to the structure.
Local $iState = 0, $i, $iTimer
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
ExitLoop
Case $msg = $instructions
MsgBox(0, "Instructions", "1.) Log in to Facebook (if not already) in the window below" & #CRLF & "2.) Clear any notifications and get to the map screen" & #CRLF & "3.) Click on the dog bowl icon on the right of the map" & #CRLF & "4.) Enter the number of dogs you have to level up" & #CRLF & "5.) Click the Begin Auto Feed Dog button at the bottom of the window")
Case $msg = $AutoLevel
$NumDogs = GUICtrlRead($NumDogsBox)
$stop = GUICtrlCreateButton('STOP', 830, 65)
$iState = 1
$i = 0
Case Else
If $iState = 1 Then
If $i >= $NumDogs Then
$iState = 3
ContinueLoop
EndIf
MsgBox(0, "", "1xp" & $i + 1)
ControlClick("[CLASS:MacromediaFlashPlayerActiveX]", "", "", "left", 1, 156, 651)
$iState = 2
$iTimer = TimerInit()
ElseIf $iState = 2 Then
If TimerDiff($iTimer) < 2000 Then ContinueLoop
ControlClick("[CLASS:MacromediaFlashPlayerActiveX]", "", "", "left", 1, 723, 524)
MsgBox(0, "", "Next Dog")
$iTimer = TimerInit()
$i = $i + 1
ElseIf $iState = 3 Then
If TimerDiff($iTimer) < 1000 Then ContinueLoop
If $i <= 0 Then
$iState = 1
ContinueLoop
EndIf
ControlClick("[CLASS:MacromediaFlashPlayerActiveX]", "", "", "left", 1, 62, 525)
MsgBox(0, "", "Previous Dog")
$iTimer = TimerInit()
$i = $i - 1
EndIf
EndSelect
WEnd

How to do this in Visual basic?

How to do the "a++" and "b++" in Visual basic?
What is the another codes for there in Vb?
The names there are just example.
int a = 0;
int b = 0;
{
if (ans1.Text == "James")
{
a++;
}
else
{
b++;
}
if (ans2.Text == "Ryan")
{
a++;
}
else
{
b++;
}
if (ans3.Text == "Mac")
{
a++;
}
else
{
b++;
}
t1.Text = a.ToString();
t2.Text = b.ToString();
}
Like this:
a += 1
b += 1
(...)
Like this
DIM a as integer = 0
DIM b as integer = 0
If ans1.Text = "James" Then
a += 1
Else
b += 1
End If
If ans2.Text = "Ryan" Then
a += 1
Else
b += 1
End If
If ans3.Text = "Mac" Then
a += 1
Else
b += 1
End If
t1.Text = a.ToString()
t2.Text = b.ToString()
Your question has already been answered but I think it would be useful to see how you could simplify your code:
Dim correctAnswers As Integer = 0
Dim totalQuestions As Integer = 3'you need to modify this is you add more questions
'increment the number of correct answers for each one we find
correctAnswers += If(ans1.text = "James", 1, 0)
correctAnswers += If(ans2.text = "Ryan", 1, 0)
correctAnswers += If(ans3.text = "Mac", 1, 0)
'show the number of correct and incorrect answers
t1.Text = correctAnswers.ToString()
t2.Text = (totalQuestions - correctAnswers).ToString() 'show the number of incorrect questions
Neither the postfix nor prefix ++ are defined in Visual Basic.
Your only realistic option is to use a = a + 1 (or, in later BASICs, a += 1) instead (note the lack of a ; for a statement terminator). But note that this will not evaluate to the previous value of a and the entire construct is not an expression in the C / C++ sense. You could build a function to mimic a++ but that would be too obfuscating.

How do I serialize a table for insertion into a database? [duplicate]

This question already has answers here:
method for serializing lua tables
(5 answers)
Closed 8 years ago.
I would like to serialize a table so that I can insert it into a database and retrieve it later on. How would I do this?
maybe like this https://gist.github.com/rangercyh/5814003
local szStr = ""
function print_lua_table (lua_table, indent)
indent = indent or 0
for k, v in pairs(lua_table) do
if type(k) == "string" then
k = string.format("%q", k)
end
local szSuffix = ""
if type(v) == "table" then
szSuffix = "{"
end
local szPrefix = string.rep(" ", indent)
formatting = szPrefix.."["..k.."]".." = "..szSuffix
if type(v) == "table" then
szStr = szStr..formatting
print_lua_table(v, indent + 1)
szStr = szStr..szPrefix.."},"
else
local szValue = ""
if type(v) == "string" then
szValue = string.format("%q", v)
else
szValue = tostring(v)
end
szStr = szStr..formatting..szValue..","
end
end
end
How to serialize Lua value nicely?
local serialize
do
local num_fmt = '%.17g'
local NaN_serialized = { -- This idea was stolen from lua-nucleo
[num_fmt:format(1/0)] = '1/0',
[num_fmt:format(-1/0)] = '-1/0',
[num_fmt:format(0/0)] = '0/0'
}
local function serialize_table(t, indent)
indent = indent or ''
local new_indent = indent..'\t'
if next(t) == nil then
return '{}'
else
local lines = {}
local function add_line(key)
local ser_key = key
if type(key) ~= 'string' or not key:find'^[%a_][%w_]*$' then
ser_key = '['..serialize(key, new_indent)..']'
end
table.insert(lines,
ser_key..' = '..serialize(t[key], new_indent))
end
local other_keys = {}
local keys = setmetatable({number = {}, string = {}},
{__index = function() return other_keys end})
for k in pairs(t) do
table.insert(keys[type(k)], k)
end
table.sort(keys.number)
table.sort(keys.string)
for _, k in ipairs(keys.number) do
add_line(k)
end
for _, k in ipairs(keys.string) do
add_line(k)
end
for _, k in ipairs(other_keys) do
add_line(k)
end
return '{\n'..new_indent..table.concat(lines, ',\n'..new_indent)
..'\n'..indent..'}'
end
end
function serialize(v, indent)
if type(v) == 'string' then
return ('%q'):format(v)
elseif type(v) == 'boolean' then
return tostring(v)
elseif type(v) == 'nil' then
return tostring(v)
elseif type(v) == 'number' then
return (num_fmt:format(v):gsub('^.*', NaN_serialized))
elseif type(v) == 'table' then
return serialize_table(v, indent)
else
error('Can not serialize '..type(v))
end
end
end
-- What it can:
print(serialize(math.huge))
print(serialize'"What\'s up?"\n\t123')
print(serialize{{}, {{}}})
-- And what it can not:
local t = {}
local tt = {[t] = t}
print(serialize(tt)) -- tt is not a tree, so it was serialized incorrectly