VBA - Regex - String in a Word - json

I'm having this type of json response:
{"success":true,"data":[{"guid":10101,"name":"name1","ispool":true,"dateadded":"2018-09-12T10:22:44","status":5,"lastactivity":"2018-09-13T03:15:06","templatechannels":[{"guid":10102,"name":"name2","iscampaign":false,,"ispool":true,"dateadded":"2018-09-12T10:22:44","status":5,"lastactivity":"2018-09-13T03:15:06","templatechannels"},{........}]}]}
I want to get all guid from this response...
It may have more than 100 records of guid. I want to have all of them.

This is regex based reading your string from a cell. If there can also be guids which you want then change the pattern passed to guids?":(\d+[^,]).
Option Explicit
Public Sub test()
Dim s As String, i As Long, arr()
s = [A1]
arr = GetMatches(s, "guid"":(\d+[^,])")
For i = LBound(arr) To UBound(arr)
Debug.Print arr(i)
Next
End Sub
Public Function GetMatches(ByVal inputString As String, ByVal sPattern As String) As Variant
Dim matches As Object, iMatch As Object, s As String, arrMatches(), i As Long
With CreateObject("vbscript.regexp")
.Global = True
.MultiLine = True
.IgnoreCase = True
.pattern = sPattern
If .test(inputString) Then
Set matches = .Execute(inputString)
ReDim arrMatches(0 To matches.Count - 1)
For Each iMatch In matches
arrMatches(i) = iMatch.submatches.item(0)
i = i + 1
Next iMatch
Else
ReDim arrMatches(0)
arrMatches(0) = vbNullString
End If
End With
GetMatches = arrMatches
End Function
Regex:
Try it here.
/
guid":(\d+[^,])
/
gm
guid": matches the characters guid": literally (case sensitive)
1st Capturing Group (\d+[^,])
\d+ matches a digit (equal to [0-9])
+ Quantifier — Matches between one and unlimited times, as many times as possible, giving back as needed (greedy)
Match a single character not present in the list below [^,]
, matches the character , literally (case sensitive)
I extract the first group submatch.

if you have that string, say, in excel cell A1 you could use this:
Dim arr As Variant
Dim iArr As Long
arr = Split(Range("A1").Value, "guid")
If UBound(arr, 1) > 0 Then
For iArr = 1 To UBound(arr, 1)
MsgBox Mid(arr(iArr), 3, InStr(arr(iArr), ",") - 3)
Next
End If
edit after OP's comment
to face the "guids" vs "guid" occurrence you could first change all "guids" to "guid" with Replace() function
arr = Split(Replace(Range("A1").Value, "guids", "guid"), "guid")

Related

Search string in between HTML tags and replace

Newbie here. I have an HTML source code and would like to look for string in between header tags <h1></h1>, <h2></h2>till <h5></h5> and then convert the text to lower case except acronyms or abbreviations (these are all capitals in 2 or more characters). And make sure that all country names in between use proper case.
As an example: It will find <h1>HR Policies and Procedures for Hiring - argentina LTD</h1>
It will convert it to:<H1>HR policies and procedures for hiring - Argentina LTD</H1>
I've tried a user defined function for Excel VBA found online: CapIt(A2). It uses Search, Split and Join. I'm not able to put them together to come up with the result. Would appreciate very much your help. Thank you.
Code I saw online as initial reference:
Function Capit(s As String)
Dim v As Variant, j As Long
v = Split(s, " ") ' separates the words
For j = LBound(v) To UBound(v)
If StrComp(v(j), UCase(v(j)), vbBinaryCompare) <> 0 Then v(j) = StrConv(v(j), vbProperCase)
Next j
Capit = Join(v, " ") ' joins the words
End Function
'Added this code below, can we use the results to lowercase the string and exclude the output in this function
Function FindAcronyms(yourWord As String)
Dim I As Integer
Dim ctr As Integer
FindAcronyms = Null
For I = 1 To Len(yourWord)
If Asc(Mid(yourWord, I, 1)) <= 90 And _
Asc(Mid(yourWord, I, 1)) >= 65 Then
If ctr > 0 Then
FindAcronyms = FindAcronyms & Mid(yourWord, I - 1, 1)
End If
ctr = ctr + 1
Else
If ctr > 1 Then
FindAcronyms = FindAcronyms & Mid(yourWord, I - 1, 1) & ", "
End If
ctr = 0
End If
Next
If ctr > 1 Then
FindAcronyms = FindAcronyms & Mid(yourWord, I - 1, 1)
End If
If Right(FindAcronyms, 2) = ", " Then
FindAcronyms = Left(FindAcronyms, Len(FindAcronyms) - 2)
End If
End Function
'the final look would be something like this
Sub TitleChange()
'define array
myarray = Range("A1:A100")
' Define the pattern
Dim pattern As String: pattern = "<h*>*</h*>" 'looks for the header tags
Dim f As Variant
For Each f In myarray
If f Like pattern = True Then Capital (f) 'changes all string to lower case except countries (to retain proper case) and acronyms (to retain uppercase)
Next f
End Sub
You can include the countries in an array
Sub Test()
Debug.Print Capital("HR Policies and Procedures for Hiring - argentina LTD")
End Sub
Function Capital(ByVal s As String)
Dim a, v As Variant, j As Long
a = Array("Argentina", "Egypt", "Enland")
v = Split(s, " ")
For j = LBound(v) To UBound(v)
If StrComp(v(j), UCase(v(j)), vbBinaryCompare) <> 0 Then v(j) = StrConv(v(j), vbLowerCase)
If Not IsError(Application.Match(v(j), a, 0)) Then v(j) = StrConv(v(j), vbProperCase)
Next j
Capital = Join(v, " ")
End Function
Added UDF that parses HTML code, used the Sub Test above as UDF Capital and UDF to bring together. Welcome suggestions to make it cleaner or more efficient
Dim rng As Range, cell As Range
Set rng = Range("A1:A5")
' Define the pattern
Dim pattern As String: pattern = "*<h?>*</h?>*"
' Check each item against the pattern
For Each cell In rng
If (cell Like pattern = True) Then
cell.Offset(0, 16).Value = cell.Value
cell.Offset(0, 16).Value = joinCell(Capital(StripHTML(cell)), cell.Offset(0, 0).Value) 'used UDF for striping innertext, applying rules and joining back string
End If
Next cell
End Sub

Sorting in MS Access

I would like to sort data in MS Access, and for that I am using a query. The data in my table is like:
RadButtonNo
-------------------
AA001056
AA001579
B000049
AA001261
AA001158
AA001108
AA001166
AA001165
AA001164
AA001163
AA001162
For my output, the data I would like first would be only data which consists of letters. Following that, I would like to display letters and numbers. So, it would look something like this:
AAAAAAA
AABBBBB
AAZZZZZ
ABA1001
I am using the following query:
SELECT RadButtonNo, ShortName, InspectionDate, Findings, Status, QueryForNot1.Initials, DeptName, Lost, TableApron.InServelDate, TableApron.RemovedDate,
TableApron.PrivateUserName, TableApron.PrivateUserEmail, TableApron.ApronType, TableApron.Manufacturer
FROM TableApron
LEFT JOIN QueryForNot1 ON TableApron.RadButtonNo=QueryForNot1.RadButtonNoI
WHERE (((TableApron.Lost)="N" Or (TableApron.Lost)=[#Lost])
ORDER BY LEN(TableApron.RadButtonNo) DESC , TableApron.RadButtonNo;
Can someone fix this so that it will produce my desired output?
You can use these two functions:
Public Function TrimNumString( _
ByVal strNumString As String, _
Optional ByVal strDecimalChr As String, _
Optional ByVal booAcceptMinus As Boolean) _
As String
' Removes any non-numeric character from strNumString including hexadecimal characters.
' If strDecimalChr is specified, first occurrence of this is not removed.
' If booAcceptMinus is True, a leading or trailing minus sign is accepted.
'
' 1999-08-27. Cactus Data ApS, CPH.
' 2001-06-21. Speed optimized for large string (64 K).
' 2003-12-10. intOffset changed to lngOffset.
Const cbytNeg As Byte = 45 ' "-"
Dim lngPos As Long
Dim lngLen As Long
Dim lngOffset As Long
Dim booDec As Boolean
Dim booNeg As Boolean
Dim bytChr As Byte
Dim bytDec As Byte
Dim strNum As String
strNumString = Trim(strNumString)
lngLen = Len(strNumString)
If lngLen > 0 Then
If Len(strDecimalChr) > 0 Then
bytDec = Asc(strDecimalChr)
End If
' Create empty result string of maximum possible length.
strNum = Space(lngLen)
For lngPos = 1 To lngLen
bytChr = Asc(Mid(strNumString, lngPos, 1))
Select Case bytChr
Case 48 To 57
' Digit.
Case bytDec
' Decimal point.
If booDec = False Then
' One decimal point only.
booDec = True
End If
Case cbytNeg
' Minus sign.
bytChr = 0
If booAcceptMinus = True And booNeg = False Then
If Len(Trim(strNum)) = 0 Or lngPos = lngLen Then
bytChr = cbytNeg
' One minus sign only.
booNeg = True
End If
End If
Case Else
' Ignore any other character.
bytChr = 0
End Select
If bytChr > 0 Then
' Append accepted character by inserting it in result string.
lngOffset = lngOffset + 1
Mid(strNum, lngOffset) = Chr(bytChr)
End If
Next
End If
' Trim and return result string.
TrimNumString = Left(strNum, lngOffset)
End Function
Public Function TrimTxtString( _
ByVal strTxtString As String) _
As String
' Removes any numeric character from strTxtString.
'
' 2003-12-19. Cactus Data ApS, CPH.
Dim lngPos As Long
Dim lngLen As Long
Dim lngOffset As Long
Dim bytChr As Byte
Dim strNum As String
strTxtString = Trim(strTxtString)
lngLen = Len(strTxtString)
If lngLen > 0 Then
' Create empty result string of maximum possible length.
strNum = Space(lngLen)
For lngPos = 1 To lngLen
bytChr = Asc(Mid(strTxtString, lngPos, 1))
Select Case bytChr
Case 48 To 57
' Digit.
bytChr = 0
Case Else
' Accept any other character.
End Select
If bytChr > 0 Then
' Append accepted character by inserting it in result string.
lngOffset = lngOffset + 1
Mid(strNum, lngOffset) = Chr(bytChr)
End If
Next
End If
' Trim and return result string.
TrimTxtString = Left(strNum, lngOffset)
End Function
Then adjust your SQL:
ORDER BY LEN(TableApron.RadButtonNo) DESC, TrimTxtString([TableApron].[RadButtonNo]), TrimNumString([TableApron].[RadButtonNo]);
Group entries by appending a character/or more to the entries with digits. Sort o that new field. I use here a value with all z and extra z to exclude a real entry of z's.
SELECT RadButtonNo
from tbl
order by IIF(RadButtonNo like "*#*", "zzzzzzzzz" & RadButtonNo, RadButtonNo)

checking the last word in a textbox

i have an access form consisting of a textbox , i need to check the last word of it and if this word is one of many words (array or a table column ) do an action , and this check will occurs in after_update event , something like
Private Sub textbox_AfterUpdate()
Dim txt As String
Dim lastword As String
txt = TextBox.Value
lastword= Right(txt, Len(txt) - InStrRev(txt, " "))
if lastword in (array() or column in a table) then
' do an action
End If
End Sub
we can also us an external function , could you help me with it ??
Looks like you got the function for the last word already... Now for the search in an array and table use this:
Function isInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
and
Function isColumnName(stringToBeFound As String, tableName As String) As Boolean
Dim db As Database
Dim rs1 As DAO.Recordset
Set db = CurrentDb()
Set rs1 = db.OpenRecordset(tableName)
isColumnName = False
Dim fld As DAO.Field
do until rs1.EOF
if rs1.Fields.Item(0).Value = stringToBeFound then
isColumnName = true
exit loop
end if
rs1.moveNext
loop
Set fld = Nothing
End Function
usage:
if isInArray(lastWord, youArray) or isColumnName(lastWord, "yourTable")
MsgBox "The word is already used!"
end if
How about something like this:
Private Sub TextBox1_AfterUpdate()
Dim txtStr As String
Dim vWords, v
txtStr = TextBox1.Text
If InStr(txtStr, " ") > 0 Then
txtStr = Right(txtStr, Len(txt) - InStrRev(txt, " "))
End If
vWords = Split("word1 word2 word3 word4", " ") ' fill vWords with the words you need
For Each v In vWords
If v = txtStr Then
' do an action
Exit For
End If
Next
End Sub

Assigning Value of a formula to a cell

I have a data chart with many products.
I want to filter each type of product, calculate the total quantity of that type as well as the number of product inside that type. And finally put the value of that function into a column in Sheet 2.
Here is the code. The quantity column is column U. It gets error 1004: Argument not optional, and it highlights the Set .... = FunctionR1C1 = .... part
Function T_Quantity()
ActiveSheet.Range("U").Select
Total = FunctionR1C1 = "=subtotal(9,C[0])"
End Function
Function T_Count(ref_column)
ActiveSheet.Range("U").Select
Total = FunctionR1C1 = "=subtotal(2,C[0])"
End Function
Sub Total_Count()
Dim my_array() As String
Dim iLoop As Integer
Dim iCount As Integer
iCount = 1
ReDim my_array(3)
my_array(0) = "=M1747B"
my_array(1) = "=M1747C"
my_array(2) = "=M1766B"
For iLoop = LBound(my_array) To UBound(my_array)
ActiveSheet.Range("A:BB").Select
Selection.AutoFilter Field:=15, Criteria1:=my_array
Application.CutCopyMode = False
'Calculate the quantity and no of lot, put in colum A,B in sheet 2'
Set Worksheets("Sheet2").Cells(iCount, 1) = T_Quantity()
Set Worksheets("Sheet2").Cells(iCount, 2) = T_Count()
Application.CutCopyMode = False
iCount = iCount + 1
Next iLoop
End Sub
Let's start with this and see if that gets you any closer to your desired results:
Sub Total_Count()
Dim my_array() As String
Dim iLoop As Integer
Dim iCount As Integer
iCount = 1
ReDim my_array(3)
my_array(0) = "=M1747B"
my_array(1) = "=M1747C"
my_array(2) = "=M1766B"
For iLoop = LBound(my_array) To UBound(my_array)
ActiveSheet.Range("A:BB").Select
Selection.AutoFilter Field:=15, Criteria1:=my_array
Application.CutCopyMode = False
'Calculate the quantity and no of lot, put in colum A,B in sheet 2'
Worksheets("Sheet2").Cells(iCount, 1).FormulaR1C1 = "=subtotal(9,C[0])"
Worksheets("Sheet2").Cells(iCount, 2).FormulaR1C1 = "=subtotal(2,C[0])"
Application.CutCopyMode = False
iCount = iCount + 1
Next iLoop
End Sub
What I changed:
Eliminate the Set keyword when working with cell objects on the Worksheet. Set is used to assign object variables.
Since the functions you call appear to be simply setting the cell's FormulaR1C1 property, I add the .FormulaR1C1 property to those lines, and then, instead of using a Function, I simply put the function's R1C1 notation directly in this subroutine.

importing comma delimited csv file with commas in long numbers

I am trying to import a comma delimted csv file in access. The issue i am having is that one of the columns "Amount" has commas in the data itself e.g. "1,433.36". And there will always be commas in this data.
How can I import is successfully?
Sample Data:
sjonn,one,"1,855.9"
ptele,two,344.0
jrudd,one,334.8
Thanks in advance
I would change the delimiter to a different character, like a pipe "|".
if the DoCmd.TransferText does not work for you, then you can define a method to do that 'manually' :
Set fs = Server.CreateObject("Scripting.FileSystemObject")
Set objFile = fs.GetFile("import.txt")
Set objFileTextStream = objFile.OpenAsTextStream(1, 2)
objFileTextStream.skipLine 'if the file contains the header
Do While objFileTextStream.AtEndOfStream <> True
strLine = objFileTextStream.ReadLine 'read a line
strLinePart = split(strLine,",") 'Split the line using the , delimiter
firstField = strLinePart(0)
secondField = strLinePart(1)
thirdField = strLinePart(2)
strSQL = "INSERT INTO myTable Values('"& firstField &"','"& secondField &"','"& thirdField &"')"
conn.Execute strSQL
Loop
objFileTextStream.Close: Set objFileTextStream = Nothing
Set fs = Nothing
conn.Close: Set conn = Nothing
Save the file as a tab delimited text file and import that instead.
reading the file using input handles the quotes for you
Dim f1 As String
Dim f2 As String
Dim f3 As String
Open "d:\test.txt" For Input As #1
Input #1, f1, f2, f3
Debug.Print f1, f2, f3
Input #1, f1, f2, f3
Debug.Print f1, f2, f3
Close #1 '
giving
sjonn one 1,855.9
ptele two 344.0
I once encountered the problem and this is another method that might help, it however splits the lines themselves, i.e. you must split the string first into lines before using this method
Its also assumed that its contained in a Module named Module1
''Perfoms a smart split that takes care of the ""
Public Function SmartSplit(Str As String) As Variant
''New collection
Dim Quote As String
Dim Delimiter As String
Dim MyString As String
Dim Sample As String
Dim StrCollection As New Collection
Dim Array_1() As String
Dim HasSeenQuote As Boolean
Dim index As Long
Quote = "" & CStr(Chr(34))
Delimiter = "" & CStr(Chr(44))
HasSeenQuote = False
Array_1 = Split(Str, Delimiter)
For index = LBound(Array_1) To UBound(Array_1)
Sample = Array_1(index)
If Module1.StartsWith(Sample, Quote, False) Then
HasSeenQuote = True
End If
''We append the string
If HasSeenQuote Then
MyString = MyString & "," & Sample
End If
''We add the term
If Module1.EndsWith(Sample, Quote, False) Then
HasSeenQuote = False
MyString = Replace(MyString, Quote, "")
MyString = Module1.TrimStartEndCharacters(MyString, ",", True)
MyString = Module1.TrimStartEndCharacters(MyString, Quote, True)
StrCollection.Add (MyString)
MyString = ""
GoTo LoopNext
End If
''We did not see a quote before
If HasSeenQuote = False Then
Sample = Module1.TrimStartEndCharacters(Sample, ",", True)
Sample = Module1.TrimStartEndCharacters(Sample, Quote, True)
StrCollection.Add (Sample)
End If
LoopNext:
Next index
''Copy the contents of the collection
Dim MyCount As Integer
MyCount = StrCollection.Count
Dim RetArr() As String
ReDim RetArr(0 To MyCount - 1) As String
Dim X As Integer
For X = 0 To StrCollection.Count - 1 ''VB Collections start with 1 always
RetArr(X) = StrCollection(X + 1)
Next X
SmartSplit = RetArr
End Function
''Returns true of false if the string starts with a string
Public Function EndsWith(ByVal Str As String, Search As String, IgnoreCase As Boolean) As Boolean
EndsWith = False
Dim X As Integer
X = Len(Search)
If IgnoreCase Then
Str = UCase(Str)
Search = UCase(Search)
End If
If Len(Search) <= Len(Str) Then
EndsWith = StrComp(Right(Str, X), Search, vbBinaryCompare) = 0
End If
End Function
''Trims start and end characters
Public Function TrimStartEndCharacters(ByVal Str As String, ByVal Search As String, ByVal IgnoreCase As Boolean) As String
If Module1.StartsWith(Str, Search, IgnoreCase) Then
Str = Right(Str, (Len(Str) - Len(Search)))
End If
If Module1.EndsWith(Str, Search, IgnoreCase) Then
Str = Left(Str, (Len(Str) - Len(Search)))
End If
TrimStartEndCharacters = Str
End Function
''Returns true of false if the string starts with a string
Public Function StartsWith(ByVal Str As String, Search As String, IgnoreCase As Boolean) As Boolean
StartsWith = False
Dim X As Integer
X = Len(Search)
If IgnoreCase Then
Str = UCase(Str)
Search = UCase(Search)
End If
If Len(Search) <= Len(Str) Then
StartsWith = StrComp(Left(Str, X), Search, vbBinaryCompare) = 0
End If
End Function