New to MS Access. Had a question regarding formatting of a MAC Address in one of my Access forms. There is a field I have set up using an input mask aa:aa:aa:aa:aa:aa;;a where users can manually enter a 48 bit hexidecimal address. e.x 11:44:5E:33:53:AF.
However sometimes there are missing values that occur in this data entry e.x 0:A:B:11:22:C (happens from time to time) but I would like be able to automatically fill the missing values with leading zeros to be like 00:0A:0B:11:22:0C.
I realize that this may not be possible through just MS Access Input masks, but all of the VBA codes and after updates code building I have been looking at so far have not lead me to the desired format.
Thanks for your time and appreciate any help in this!
I tried Format(fieldname, "00000000") code, but it just fills from the left-hand side instead of between the colons. e.x 00:00:0A:B1:12:2C instead of the desired 00:0A:0B:11:22:0C.
My function FormatMacAddress is for you:
' Formats a MAC address using one of the four de facto formats used widely.
' Thus, the format can and will be defined by the specified delimiter to use.
' The default is no delimiter and uppercase.
' Optionally, the case of the returned string can be specified as lowercase.
'
' Examples:
' None -> "1234567890AB"
' Dot -> "1234.5678.90AB"
' Dash -> "12-34-56-78-90-AB"
' Colon -> "12:34:56:78:90:AB"
'
' Lowercase -> "1234567890ab"
'
' 2019-09-23, Cactus Data ApS, Gustav Brock
'
Public Function FormatMacAddress( _
ByRef Octets() As Byte, _
Optional Delimiter As IpMacAddressDelimiter, _
Optional TextCase As VbStrConv = VbStrConv.vbProperCase) _
As String
Dim LastFrame As Integer
Dim ThisFrame As Integer
Dim FrameLength As Integer
Dim Index As Integer
Dim Symbol As String
Dim MacAddress As String
' Only accept an array with six octets.
If LBound(Octets) = 0 And UBound(Octets) = OctetCount - 1 Then
' Calculate the frame length.
FrameLength = DigitCount / DelimiterFrameCount(Delimiter)
' Format the octets using the specified delimiter.
For Index = LBound(Octets) To UBound(Octets)
ThisFrame = (Index * OctetLength) \ FrameLength
Symbol = ""
If LastFrame < ThisFrame Then
Symbol = DelimiterSymbol(Delimiter)
LastFrame = ThisFrame
End If
MacAddress = MacAddress & Symbol & Right("0" & Hex(Octets(Index)), OctetLength)
Next
End If
If MacAddress <> "" Then
Select Case TextCase
Case VbStrConv.vbLowerCase
MacAddress = StrConv(MacAddress, TextCase)
Case Else
' Leave MacAddress in uppercase.
End Select
End If
FormatMacAddress = MacAddress
End Function
As it requires a Byte() input, you may need the function MacAddressParse as well:
' Parses a string formatted MAC address and returns it as a Byte array.
' Parsing is not case sensitive.
' Will by default only accept the four de facto standard formats used widely.
'
' Examples:
' "1234567890AB" -> 1234567890AB
' "1234.5678.90AB" -> 1234567890AB
' "12-34-56-78-90-AB" -> 1234567890AB
' "12:34:56:78:90:AB" -> 1234567890AB
'
' If argument Exact is False, a wider variation of formats will be accepted:
' "12-34:56-78:90-AB" -> 1234567890AB
' "12 34 56-78 90 AB" -> 1234567890AB
' "56 78 90 AB" -> 0000567890AB
' "1234567890ABDE34A0" -> 1234567890AB
'
' For unparsable values, the neutral MAC address is returned:
' "1K34567890ABDEA0" -> 000000000000
'
' 2019-09-23, Cactus Data ApS, Gustav Brock
'
Public Function MacAddressParse( _
ByVal MacAddress As String, _
Optional Exact As Boolean = True) _
As Byte()
Dim Octets() As Byte
Dim Index As Integer
Dim Expression As String
Dim Match As Boolean
' Delimiters.
Dim Colon As String
Dim Dash As String
Dim Dot As String
Dim Star As String
' Create neutral MAC address.
ReDim Octets(0 To OctetCount - 1)
' Retrieve delimiter symbols.
Colon = DelimiterSymbol(ipMacColon)
Dash = DelimiterSymbol(ipMacDash)
Dot = DelimiterSymbol(ipMacDot)
Star = DelimiterSymbol(ipMacStar)
If Exact = True Then
' Verify exact pattern of the passed MAC address.
Select Case Len(MacAddress)
Case TotalLength1
' One frame of six octets (no delimiter).
Expression = Replace(Space(DigitCount), Space(1), HexPattern)
Match = MacAddress Like Expression
If Match = True Then
' MAC address formatted as: 0123456789AB.
End If
Case TotalLength3
' Three frames of two octets.
Expression = Replace(Replace(Replace(Space(DigitCount / FrameLength3), Space(1), Replace(Replace(Space(FrameLength3), Space(1), HexPattern), "][", "]" & Star & "[")), "][", "]" & Dot & "["), Star, "")
Match = MacAddress Like Expression
If Match = True Then
' MAC address formatted as: 0123.4567.89AB.
MacAddress = Replace(MacAddress, Dot, "")
End If
Case TotalLength6
' Six frames of one octets.
Expression = Replace(Replace(Replace(Space(DigitCount / FrameLength6), Space(1), Replace(Replace(Space(FrameLength6), Space(1), HexPattern), "][", "]" & Star & "[")), "][", "]" & Colon & "["), Star, "")
Match = MacAddress Like Expression
If Match = True Then
' MAC address formatted as: 01:23:45:67:89:AB.
MacAddress = Replace(MacAddress, Colon, "")
Else
Expression = Replace(Expression, Colon, Dash)
Match = MacAddress Like Expression
If Match = True Then
' MAC address formatted as: 01-23-45-67-89-AB.
MacAddress = Replace(MacAddress, Dash, "")
End If
End If
End Select
Else
' Non-standard format.
' Clean MacAddress and try to extract six octets.
MacAddress = Replace(Replace(Replace(Replace(MacAddress, Colon, ""), Dash, ""), Dot, ""), Space(1), "")
Select Case Len(MacAddress)
Case Is > DigitCount
' Pick leading characters.
MacAddress = Left(MacAddress, DigitCount)
Case Is < DigitCount
' Fill with leading zeros.
MacAddress = Right(String(DigitCount, "0") & MacAddress, DigitCount)
End Select
' One frame of six possible octets.
Expression = Replace(Space(DigitCount), Space(1), HexPattern)
Match = MacAddress Like Expression
If Match = True Then
' MAC address formatted as: 0123456789AB.
End If
End If
If Match = True Then
' Fill array Octets.
For Index = LBound(Octets) To UBound(Octets)
Octets(Index) = Val("&H" & Mid(MacAddress, 1 + Index * OctetLength, OctetLength))
Next
End If
MacAddressParse = Octets
End Function
Full code at GitHub: VBA.MacAddress.
Related
I try to trim spaces in Calc using a macro.
The Trim function doesn't seem to work
I tried using Trim, LTrim, RTrim but same result.
Anybody have an idea of where is wrong?
oCSL is "Arang and the Magistrate"
oCSR and z should also be like oCSL after Trim but still stays "Arang and the Magistrate "
Code below:
Dim oAC As Object, oC As Object, oAS As Object, oCSL As String, oCSR As String
Dim oASn As Integer
Dim CellRangeAddress As New com.sun.star.table.CellRangeAddress
Dim CellAddress As New com.sun.star.table.CellAddress
oC = ThisComponent
oAS = oC.getcurrentcontroller.ActiveSheet
oASn = oC.getCurrentController().getActiveSheet().getRangeAddress().sheet
Dim Ll As Integer, Lc As Integer, r As Integer
Dim z As String, y As String
Ll = 400
Lc = 0
r = 400
' Read Each Left Side Line
Do
Do
' Locate Position For Right Side
Do
oCSL = Trim(UCase(oAS.getCellByPosition(Lc, Ll).String)) ' oSCL Value Returned "Arang and the Magistrate"
oCSR = Trim(UCase(oAS.getCellByPosition(7, r).String)) ' oCSR Value Returned "Arang and the Magistrate "
z = RTrim(oAS.getCellByPosition(7, r).String) ' z Returns Also "Arang and the Magistrate "
If strcomp(oCSL, oCSR) < 0 Then
ThisComponent.CurrentController.Select(oAS.getCellByPosition(7, r)) ' Reposition Selected Area
'ThisComponent.CurrentController.Select(oAS.getCellByPosition(Lc, Ll)) ' Reposition Selected Area
MsgBox ("At " & r & " Not Found " & Chr(13) & oCSL) ' Not Found
' Insert New Movie
Exit Do
else
If UCase(oCSL) = UCase(OcSR) Then
ThisComponent.CurrentController.Select(oAS.getCellByPosition(7, r)) ' Reposition Selected Area
'MsgBox ("At " & r & " Same Value " & oCSL) ' Same Value
r = r + 1
Exit Do
else
r = r + 1
End If
End If
Loop While Lc <= 4
Lc = Lc + 1
Loop While Lc <= 4
Ll = Ll + 1 ' Next Line
Lc = 0 ' Reset Column
Loop While oCSL <> "" ' getCellByPosition Starts From Col 0 Row 0
I found the reason.
After using Asc() in order to figuring out if it's spaces and it wasn't spaces but special characters.
Sorry for bothering everybody.
I need a Classic ASP function that will take a string such as Jämshög and convert it to J\u00e4msh\u00f6gso that all the accented characters become their equivalent unicode escape codes.
I am sending this data in a JSON string to an API that requires all special characters to use unicode escape codes.
I've been searching for what seems like hours to come up with a solution and I haven't managed to come close. Any help would be greatly appreciated.
Take a look at the function from aspjson below. It also handles non-unicode characters that must to be escaped such as quote, tab, line-feed etc. Luckily no dependencies, so works stand-alone too.
Function jsEncode(str)
Dim charmap(127), haystack()
charmap(8) = "\b"
charmap(9) = "\t"
charmap(10) = "\n"
charmap(12) = "\f"
charmap(13) = "\r"
charmap(34) = "\"""
charmap(47) = "\/"
charmap(92) = "\\"
Dim strlen : strlen = Len(str) - 1
ReDim haystack(strlen)
Dim i, charcode
For i = 0 To strlen
haystack(i) = Mid(str, i + 1, 1)
charcode = AscW(haystack(i)) And 65535
If charcode < 127 Then
If Not IsEmpty(charmap(charcode)) Then
haystack(i) = charmap(charcode)
ElseIf charcode < 32 Then
haystack(i) = "\u" & Right("000" & Hex(charcode), 4)
End If
Else
haystack(i) = "\u" & Right("000" & Hex(charcode), 4)
End If
Next
jsEncode = Join(haystack, "")
End Function
This code basically takes a mathematical expression and evaluates it.
The following code i have written in VB.net shamelessly taken from here : Expression Evaluation
which has been written in Java.
Public Function evaluate(expression As [String]) As Integer
Dim tokens As Char() = expression.ToCharArray()
' Stack for numbers: 'values'
Dim values As New Stack(Of UInteger)()
' Stack for Operators: 'ops'
Dim ops As New Stack(Of Char)()
For i As Integer = 0 To tokens.Length - 1
' Current token is a whitespace, skip it
If tokens(i) = " "c Then
Continue For
End If
' Current token is a number, push it to stack for numbers
If tokens(i) >= "0"c AndAlso tokens(i) <= "9"c Then
Dim sbuf As New StringBuilder(100)
'Dim sbuf As New String("", 128)
' There may be more than one digits in number
If i < tokens.Length AndAlso tokens(i) >= "0"c AndAlso tokens(i) <= "9"c Then
sbuf.Append(tokens(System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)))
End If
If sbuf Is Nothing AndAlso sbuf.ToString().Equals("") Then
Else
Dim intgr As Integer
Dim accpt As Boolean = Integer.TryParse(sbuf.ToString(), intgr)
If accpt = True Then
values.Push([Integer].Parse(sbuf.ToString()))
Else
Dim space As String = " "
values.Push(space)
End If
End If
' Current token is an opening brace, push it to 'ops'
ElseIf tokens(i) = "("c Then
ops.Push(tokens(i))
' Closing brace encountered, solve entire brace
ElseIf tokens(i) = ")"c Then
While ops.Peek() <> "("c
values.Push(applyOp(ops.Pop(), values.Pop(), values.Pop()))
End While
ops.Pop()
' Current token is an operator.
ElseIf tokens(i) = "+"c OrElse tokens(i) = "-"c OrElse tokens(i) = "*"c OrElse tokens(i) = "/"c Then
' While top of 'ops' has same or greater precedence to current
' token, which is an operator. Apply operator on top of 'ops'
' to top two elements in values stack
While Not ops.Count = 0 AndAlso hasPrecedence(tokens(i), ops.Peek())
values.Push(applyOp(ops.Pop(), values.Pop(), values.Pop()))
End While
' Push current token to 'ops'.
ops.Push(tokens(i))
End If
Next
' Entire expression has been parsed at this point, apply remaining
' ops to remaining values
While Not ops.Count = 0
values.Push(applyOp(ops.Pop(), values.Pop(), values.Pop()))
End While
' Top of 'values' contains result, return it
Return values.Pop()
End Function
Public Function hasPrecedence(op1 As Char, op2 As Char) As [Boolean]
If op2 = "("c OrElse op2 = ")"c Then
Return False
End If
If (op1 = "*"c OrElse op1 = "/"c) AndAlso (op2 = "+"c OrElse op2 = "-"c) Then
Return False
Else
Return True
End If
End Function
' A utility method to apply an operator 'op' on operands 'a'
' and 'b'. Return the result.
Public Function applyOp(op As Char, b As Integer, a As Integer) As Integer
Select Case op
Case "+"c
Return a + b
Case "-"c
Return a - b
Case "*"c
Return a * b
Case "/"c
If b = 0 Then
'Throw New UnsupportedOperationException("Cannot divide by zero")
End If
Return a \ b
End Select
Return 0
End Function
this is how im using the code :
formula = "10 + 2 * 6"
Dim result As Double = evaluate(formula)
and i keep getting this following error:
Unhandled exception at line 885, column 13 in http:**** DEDOM5KzzVKtsL1tWZwgsquruscgqkpS5bZnMu2kotJDD8R38OukKT4TyG0z97U1A8ZC8o0wLOdVNYqHqQLlZ9egcY6AKpKRjQWMa4aBQG1Hz8t_HRmdQ39BUIKoCWPik5bv4Ej6LauiiQptjuzBMLowwYrLGpq6dAhVvZcB-4b-mV24vCqXJ3jbeKi0&t=6119e399
0x800a139e - Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: Conversion from string " " to type 'UInteger' is not valid.
Im a beginner but i think that the error is occurring because its not able to covert space into integer.How to deal with the spaces??
Any help is much appreciated:).
VB.NET is strongly-typed, so you simply cannot push anything other than integers onto a Stack(Of Integer). Therefore this code:
Dim space As String = " "
values.Push(space)
will always fail at runtime. (By the way, you want to set Option Explicit On and Option Strict On at the top of every module. If you do that, the line above will already be marked as an error at build time).
I haven't tried executing your code, but why would you need to save the spaces if what you're building is an expression evaluator? It doesn't seem to add anything to the evaluation. Perhaps if you simply don't add the spaces to the stack it will work anyway.
I wrote vbscript function which search the list of free ports on Unix. So my code looks like this:
Function FindFreePorts(ByVal intPortToStart, ByVal intCountOfPortToSearch, ByVal arrFreePorts)
Dim i, arrCommand, arrTmp, blnFindAllPort, j, strCommand
Dim blnFree, intCountOfFreePorts
strCommand = "lsof -i | awk '{print $8}' | sed -n '/"
For i = intPortToStart To intPortToStart+intCountOfPortToSearch - 1
If i = intPortToStart+intCountOfPortToSearch - 1 Then
strCommand = strCommand & ".*"& i & "$/s/.*://p'"
Else
strCommand = strCommand & ".*:" & i &"\|"
End If
Next
Push arrCommand, strCommand
arrTmp = Array()
arrTmp = ExecuteCommandOnUnix(arrCommand, Null, _
Environment.Value("UNIXHOST_NAME"), _
Environment.Value("UNIXHOST_USER"), _
Environment.Value("UNIXHOST_PWD"))
' Count of busy port is UBound(arrTmp) - the other ports are free
' Find free ports
intCountOfFreePorts = intCountOfPortToSearch
For i = intPortToStart To intPortToStart+intCountOfPortToSearch - 1
blnFree = True
For j = 0 To UBound(arrTmp)
If arrTmp(j) = CStr(i) Then
blnFree = False
j = UBound(arrTmp)
End If
Next
If blnFree Then
Push arrFreePorts, i
intCountOfFreePorts = intCountOfFreePorts - 1
End If
Next
'
If intCountOfFreePorts = 0 Then
blnFindAllPort = True
Else
blnFindAllPort = False
End If
If Not blnFindAllPort Then
' We found UBound(arrFreePorts), we need to find intCountOfPortToSearch - UBound(arrFreePorts)
Do While intCountOfPortToSearch - UBound(arrFreePorts) - 1 <> 0
arrFreePorts = FindFreePorts(intPortToStart + intCountOfPortToSearch + 1, intCountOfPortToSearch - UBound(arrFreePorts) - 1, arrFreePorts)
If intCountOfPortToSearch - UBound(arrFreePorts) - 1 = 0 Then
Exit Do
End If
Loop
End If
FindFreePorts = arrFreePorts
End Function
As you can see I call this function recursively in Do While cycle. Everything works ok but I don't like arrFreePorts parameter here. So I should write this code to execute my function:
arrPort = FindFreePorts(intStartFromPort, intCountToSearch, arrPort)
But I have no idea how to rewrite this function without this parameter. Then I could call it in more simple way:
arrPort = FindFreePorts(intStartFromPort, intCountToSearch)
Thanks in advance.
To keep things (experiments, illustration of #Bond's contribution) simple, let's consider the task of putting the chars of a string into an array.
A function that shall return an array (without getting it via parameter or global) needs to create the array:
Function f1(s) ' default ByRef is ok, because Left and Mid return new (sub)strings
If "" = s Then
f1 = Array() ' return empty array for empty string
Else
Dim t : t = f1(Mid(s, 2)) ' recurse for tail - sorry no tail recursion
f1 = cons(Left(s, 1), t) ' copy! result of cons to f1/function's return value
End If
End Function
The growing of the array could be done inline, but for clarity I use a helper function cons():
Function cons(e, a) ' default ByRef is ok; neither e nor a are changed
ReDim aTmp(UBound(a) + 1) ' create larger array
Dim i : i = 0
aTmp(i) = e ' 'new' head
For i = 1 To UBound(aTmp)
aTmp(i) = a(i - 1) ' copy 'old' elms
Next
cons = aTmp ' copy! aTmp to cons/function's return value
End Function
Calling the function is nice:
WScript.Echo 3, "[" & Join(f1("12456789"), ",") & "]"
The price to pay for avoiding the passing of 'the' array:
a lot of copies (array assingment copies in VBScript)
no tail recursion (I doubt, however, that VBScript exploits it)
about factor 10 slower than the Sub approach ((c) Bond) below
As in this case the recursive calls can/should work on the 'same' array, a Sub does the task more efficiently (and is less complex):
Sub s1(s, a) ' default ByRef is ok; a should be modified, s isn't touched
If "" <> s Then
ReDim Preserve a(UBound(a) + 1) ' grow! a
a(UBound(a)) = Left(s, 1)
s1 Mid(s, 2), a ' tail recursion for tail
End If
End Sub
Calling it looks nasty:
ReDim a(-1) : s1 "123456789", a : WScript.Echo 3, "[" & Join(a, ",") & "]"
But that can be avoided by a wrapper:
Function f2(s)
ReDim aTmp(-1)
s1 s, aTmp
f2 = aTmp
End Function
I've tried all the ways I see to add a month to a certain date then return that in a specific format but I'm at a loss. Here's my code but I need to format it:
replace( formatdatetime( dateadd( "m" , 1 , request("date") ), 0 ) , "/" , "-" ) & "' )
request("date") is in yyyyy-dd-mm hh:mm:ss format and that's how I need the new date.
The following should work perfect:
replace( formatdatetime( dateadd( "m" , 1 , cDate(request("date")) ), 0 ) , "/" , "-" )
Notice the use of the cDate function to convert a value to a date explicitly.
Edit:
I removed last part of your code & "' ), it gave me an error otherwise.
When working with dates, it's especially important to take care of the proper data (sub)types. Feeding a string to a function that expects a date (and relying on 'VBScript - and your local settings - will do the right thing') is dangerous.
Using replace will never change the order of the date parts.
FormatDateTime depends on the local/regional settings and should be avoided as a sure path to disaster.
One way to solve this problem + most of all other problems concerning fancy formatting in VBScript is to use a .Net System.Text.StringBuilder:
Given Lib.vbs:
' Lib.vbs - simple VBScript library/module
' use
' ExecuteGlobal goFS.OpenTextFile(<PathTo\Lib.vbs>).ReadAll()
' to 'include' Lib.vbs in you main script
Class ToBeAShamedOf
Public a
Public b
End Class ' ToBeAShamedOf
Class cFormat
Private m_oSB
Private Sub Class_Initialize()
Set m_oSB = CreateObject("System.Text.StringBuilder")
End Sub ' Class_Initialize
Public Function formatOne(sFmt, vElm)
m_oSB.AppendFormat sFmt, vElm
formatOne = m_oSB.ToString()
m_oSB.Length = 0
End Function ' formatOne
Public Function formatArray(sFmt, aElms)
m_oSB.AppendFormat_4 sFmt, (aElms)
formatArray = m_oSB.ToString()
m_oSB.Length = 0
End Function ' formatArray
End Class ' cFormat
and main.vbs:
' main.vbs - demo use of library/module Lib.vbs
' Globals
Dim gsLibDir : gsLibDir = ".\"
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject")
' LibraryInclude
ExecuteGlobal goFS.OpenTextFile(goFS.BuildPath(gsLibDir, "Lib.vbs")).ReadAll()
WScript.Quit demoDateFormat()
WScript.Quit main()
Function main()
Dim o : Set o = New ToBeAShamedOf
o.a = 4711
o.b = "whatever"
WScript.Echo o.a, o.b
main = 1 ' can't call this a success
End Function ' main
Function demoDateFormat()
Dim sD : sD = "2012-05-16 01:02:03" ' near future; not yyyyy!
Dim dtD : dtD = CDate(sD)
Dim dtDM : dtDM = DateAdd("m", 1, dtD)
Dim oFmt : Set oFmt = New cFormat
WScript.Echo oFmt.formatArray( _
" sD: {1}{0} dtD: {2}{0} dtDM: {3}{0}dtDM': {4}" _
, Array(vbCrLf, sD, dtD, dtDM, oFmt.formatOne("{0:yyyy-MM-dd hh:mm:ss}", dtDM)))
demoDateFormat = 0 ' seems to be decent
End Function ' demoDateFormat
you'll get:
cscript main.vbs
sD: 2012-05-16 01:02:03
dtD: 16.05.2012 01:02:03
dtDM: 16.06.2012 01:02:03
dtDM': 2012-06-16 01:02:03
(to be seen in the context of this answer)
This may help:
FormatDateTime(DateAdd("M",1,DateSerial(Left(request("date"),4),Mid(request("date"),9,2),Mid(request("date"),6,2))) & " " & Mid(request("date"),12,8),d,0)
It basically converts the string to a valid date in the native format, adds the 1 requested month and then rebuilds the string.
NOTE: request("date") looks as though it returns the current datetime so running it in this way may generate a final value that is a second or so out, if that's a problem then you will be better storing a static value in a variable, otherwise this should hopefully be ok.