Regex multiline option is not recognized by access - ms-access

I have the a myRegex function to extract Regexes from a string. When I run a query that uses the function I get the following error on multiline.
Method or data member not found.
This is the regex Function:
Function myRegex(ByRef myString As String, ByVal pattern As String) As String
Dim rgx As New RegExp
Dim colMatches As MatchCollection
With rgx
.pattern = pattern
.ignoreCase = True
.Global = False
.Multiline = False
Set colMatches = .Execute(myString)
End With
If colMatches.Count > 0 Then
myRegex = colMatches(0).Value
Else
myRegex = ""
End If
End Function
This is the query I used:
SELECT myRegex(phone,"[0-9]+")
FROM table1
I have the following reference libraries checked:
Microsoft VBScript Regular Expressions 1.0
Microsoft VBScript Regular Expressions 5.5

The following line
Dim rgx As New RegExp
...matches RegExp with the first library that defines that Class, which is
Microsoft VBScript Regular Expressions 1.0
This is an older version that does not support the Multiline property. You need the RegExp class from:
Microsoft VBScript Regular Expressions 5.5
So either:
Remove the link with that older 1.0 reference library, or
Qualify the RegExp class as VBScript_RegExp_55.RegExp, or
Use late binding (slower), with CreateObject("VBScript.RegExp")

You can uncheck the first VBScript Regular Expressions reference ... the 1.0 version ... as #trincot suggests.
Or you could uncheck both references and use late binding:
'Dim rgx As New RegExp
Dim rgx As Object
Set rgx = CreateObject("VBScript.RegExp")
However, since your query will call the function repeatedly, you may notice better performance with a Static object variable.
Function myRegex(ByRef myString As String, ByVal pattern As String) As String
Static rgx As Object
Dim colMatches As Object
If rgx Is Nothing Then
' create the RegExp object just once
Set rgx = CreateObject("VBScript.RegExp")
With rgx
.ignoreCase = True
.Global = False
.Multiline = False
End With
End If
rgx.pattern = pattern
Set colMatches = rgx.Execute(myString)
If colMatches.Count > 0 Then
myRegex = colMatches(0).Value
Else
myRegex = ""
End If
End Function

Related

I'm getting stuck at vba runtime error 424

I'm getting
run-time error 424
in 68th row (line)
request.Open "GET", Url, False
and I don't know how to fix it.
My previous question I posted ;
How to scrape specific part of online english dictionary?
My final goal is to get result like this;
A B
beginning bɪˈɡɪnɪŋ
behalf bɪˈhæf
behave bɪˈheɪv
behaviour bɪˈheɪvjər
belong bɪˈlɔːŋ
below bɪˈloʊ
bird bɜːrd
biscuit ˈbɪskɪt
Here's code I wrote, and it's mostly based on someone else's code I found on internet.
' Microsoft ActiveX Data Objects x.x Library
' Microsoft XML, v3.0
' Microsoft VBScript Regular Expressions
Sub ParseHelp()
' Word reference from
Dim Url As String
Url = "https://www.oxfordlearnersdictionaries.com/definition/english/" & Cells(ActiveCell.Row, "B").Value
' Get dictionary's html
Dim Html As String
Html = GetHtml(Url)
' Check error
If InStr(Html, "<TITLE>Not Found</Title>") > 0 Then
MsgBox "404"
Exit Sub
End If
' Extract phonetic alphabet from HTML
Dim wrapPattern As String
wrapPattern = "<span class='name' (.*?)</span>"
Set wrapCollection = FindRegexpMatch(Html, wrapPattern)
' MsgBox StripHtml(CStr(wrapCollection(1)))
' Fill phonetic alphabet into cell
If Not wrapCollection Is Nothing Then
Dim wrap As String
On Error Resume Next
wrap = StripHtml(CStr(wrapCollection(1)))
If Err.Number <> 0 Then
wrap = ""
End If
Cells(ActiveCell.Row, "C").Value = wrap
Else
MsgBox "not found"
End If
End Sub
Public Function StripHtml(Html As String) As String
Dim RegEx As New RegExp
Dim sOut As String
Html = Replace(Html, "</li>", vbNewLine)
Html = Replace(Html, " ", " ")
With RegEx
.Global = True
.IgnoreCase = True
.MultiLine = True
.Pattern = "<[^>]+>"
End With
sOut = RegEx.Replace(Html, "")
StripHtml = sOut
Set RegEx = Nothing
End Function
Public Function GetHtml(Url As String) As String
Dim xmlhttp As Object
Set xmlhttp = CreateObject("MSXML2.serverXMLHTTP")
Dim converter As New ADODB.stream
' Get
request.Open "GET", Url, False
request.send
' raw bytes
converter.Open
converter.Type = adTypeBinary
converter.Write request.responseBody
' read
converter.Position = 0
converter.Type = adTypeText
converter.Charset = "utf-8"
' close
GetHtml = converter.ReadText
converter.Close
End Function
Public Function FindRegexpMatch(txt As String, pat As String) As Collection
Set FindRegexpMatch = New Collection
Dim rx As New RegExp
Dim matcol As MatchCollection
Dim mat As Match
Dim ret As String
Dim delimiter As String
txt = Replace(txt, Chr(10), "")
txt = Replace(txt, Chr(13), "")
rx.Global = True
rx.IgnoreCase = True
rx.MultiLine = True
rx.Pattern = pat
Set matcol = rx.Execute(txt)
'MsgBox "Match:" & matcol.Count
On Error GoTo ErrorHandler
For Each mat In matcol
'FindRegexpMatch.Add mat.SubMatches(0)
FindRegexpMatch.Add mat.Value
Next mat
Set rx = Nothing
' Insert code that might generate an error here
Exit Function
ErrorHandler:
' Insert code to handle the error here
MsgBox "FindRegexpMatch. " & Err.GetException()
Resume Next
End Function
Any kind of help would be greatly appreciated.
The following is an example of how to read in values from column A and write out pronounciations to column B. It uses css selectors to match a child node then steps up to parentNode in order to ensure entire pronounciation is grabbed. There are a number of ways you could have matched on the parent node to get the second pronounciation. Note that I use a parent node and Replace as the pronounciation may span multiple childNodes.
If doing this for lots of lookups please be a good netizen and put some waits in the code so as to not bombard the site with requests.
Option Explicit
Public Sub WriteOutPronounciations()
Dim html As MSHTML.HTMLDocument, i As Long, ws As Worksheet
Dim data As String, lastRow As Long, urls()
Set ws = ThisWorkbook.Worksheets("Sheet1")
lastRow = ws.Cells(ws.rows.Count, "A").End(xlUp).row 'you need at least two words in column A or change the redim.
urls = Application.Transpose(ws.Range("A1:A" & lastRow).Value)
ReDim results(1 To UBound(urls))
Set html = New MSHTML.HTMLDocument
With CreateObject("MSXML2.ServerXMLHTTP")
For i = LBound(urls) To UBound(urls)
.Open "GET", "https://www.oxfordlearnersdictionaries.com/definition/english/" & urls(i), False
.send
html.body.innerHTML = .responseText
data = Replace$(Replace$(html.querySelector(".name ~ .wrap").ParentNode.innerText, "/", vbNullString), Chr$(10), Chr$(32))
results(i) = Right$(data, Len(data) - 4)
Next
End With
With ThisWorkbook.Worksheets(1)
.Cells(1, 2).Resize(UBound(results, 1), 1) = Application.Transpose(results)
End With
End Sub
Required references (VBE>Tools>References):
Microsoft HTML Object Library
Should you go down the API route then here is a small example. You can make 1000 free calls in a month with Prototype account. The next best, depending on how many calls you wish to make looks like the 10,001 calls (that one extra PAYG call halves the price). # calls will be affected by whether word is head word or needs lemmas lookup call first. The endpoint construction you need is GET /entries/{source_lang}/{word_id}?fields=pronunciations though that doesn't seem to filter massively. You will need a json parser to handle the json returned e.g. github.com/VBA-tools/VBA-JSON/blob/master/JsonConverter.bas. Download raw code from there and add to standard module called JsonConverter. You then need to go VBE > Tools > References > Add reference to Microsoft Scripting Runtime. Remove the top Attribute line from the copied code.
Option Explicit
Public Sub WriteOutPronounciations()
Dim html As MSHTML.HTMLDocument, i As Long, ws As Worksheet
Dim data As String, lastRow As Long, words()
'If not performing lemmas lookup then must be head word e.g. behave, behalf
Const appId As String = "yourAppId"
Const appKey As String = "yourAppKey"
Set ws = ThisWorkbook.Worksheets("Sheet1")
lastRow = ws.Cells(ws.rows.Count, "A").End(xlUp).row
words = Application.Transpose(ws.Range("A1:A" & lastRow).Value)
ReDim results(1 To UBound(words))
Set html = New MSHTML.HTMLDocument
Dim json As Object
With CreateObject("MSXML2.ServerXMLHTTP")
For i = LBound(words) To UBound(words)
.Open "GET", "https://od-api.oxforddictionaries.com/api/v2/entries/en-us/" & LCase$(words(i)) & "?fields=pronunciations", False
.setRequestHeader "app_id", appId
.setRequestHeader "app_key", appKey
.setRequestHeader "ContentType", "application/json"
.send
Set json = JsonConverter.ParseJson(.responseText)
results(i) = IIf(json("results")(1)("type") = "headword", json("results")(1)("lexicalEntries")(1)("pronunciations")(2)("phoneticSpelling"), "lemmas lookup required")
Set json = Nothing
Next
End With
With ThisWorkbook.Worksheets(1)
.Cells(1, 2).Resize(UBound(results, 1), 1) = Application.Transpose(results)
End With
End Sub

Instr Access VBA - search for Numeric followed by Letter

Sorry if this has been posted elsewhere as I could not find the answer.
I'm trying to search for any number followed by the letter "m" using the InStr function. I've got the following code which I thought should have worked however it does not recognise "1m" 1.1m" or any variation and returns 0.
Public Function instrstring(strTest As String) As Long
Dim i As Long
PosOfFirstDigit = 0
For i = 1 To Len(strTest)
If Mid$(strTest, i, 1) Like "#" & "m" Then
PosOfFirstDigit = i
Exit For
End If
Next
End Function
I appreciate your help!
To return the position of the match something like this:
For
"a1.1m"
"testme 1m"
"testme 222"
Returns
2
8
not found
Sub Impeached()
Debug.Print StrOut("a1.1m")
Debug.Print StrOut("testme 1m")
Debug.Print StrOut("testme 222")
End Sub
code
Public Function StrOut(strIn As String) As String
Dim objRegex As Object
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Pattern = "(\d*\.)?\dm"
If .Test(strIn) Then
StrOut = InStr(strIn, .Execute(strIn)(0))
Else
StrOut = "not found"
End If
End With
End Function
As #Tim Williams has mentioned, it's best using regular expressions (Regex) for this if you're having floats as well as integers.
You'll need to setup the reference to Regex to use it. Add VBA reference to "Microsoft VBScript Regular Expressions 5.5"
The regex you'll need is
Dim RE As New RegExp
With RE
.Global = True
.Pattern = "\d*?\.\dm"
End With
If RE.Test(strTest) Then
Msgbox("Found!")
'Insert the function you want to perform here
End If

Remove letter from a string access VBA

I have a string sStr that contains letters and numbers.I'm trying to remove letters from a string.
For eg: sStr= "P441" or sometimes sStr="BK471" .
I tried using
Right(sStr,3) and split
which gives me 441. since the string sStr may contain 2 letters ("BK471") sometimes, how do i remove letters in vba .
You can loop through each character in the string checking if it IsNumeric
Dim x as integer
Dim sCleanedStr As String
For x = 1 to Len(sStr)
If IsNumeric(Mid(sStr, x, 1)) then sCleanedStr = sCleanedStr & Mid(sStr, x, 1)
Next
You can use Regular Expressions to remove any letters. For this, you need to include the Regex library in your macro (Go to Tools -> References, then search and select the regular expressions library)
Sub test()
sStr = "abc123"
Dim regEx As New RegExp
With regEx
.Pattern = "[a-z]+"
.Global = True
.IgnoreCase = True
End With
sStr = regEx.Replace(sStr, "")
MsgBox (sStr)
End Sub
The above code will replace any letter from anywhere in the word.

Passing MS-Access string >255 characters to MS-Word field

I'm using .FormFields("WordBookmarkName").Result = stringFromAccess method to pass data out of MS-Access to an MS-Word document.
It seems it can only pass up to 255 characters. Is there a way I can pass more to my field in MS-Word?
Edit:
This is a simplified version of the code I was using that works ok up to 255 characters:
Dim startForms As String
Dim appWord As Word.Application
Dim doc As Word.Document
startForms = String(256, "x")
Set appWord = GetObject(, "Word.Application") 'Set appWord object variable to running instance of Word.
If Err.Number <> 0 Then
Set appWord = New Word.Application 'If Word isn't open, create a new instance of Word.
End If
Set doc = appWord.Documents.Open("C:\myFolder\MyForm.docx", , True)
With doc
.FormFields("wdStartForms").Result = "" 'Clear anything currently in the form's field
.FormFields("wdStartForms").Result = startForms
.Visible = True
.Activate
End With
Set doc = Nothing
Set appWord = Nothing
JohnnyBones: this is the code I adapted after your answer; using ActiveDocument wasn't working, so I continued to use the doc reference I'd made and it seemed to work ok with 256+ characters after that:
Dim startForms As String
Dim appWord As Word.Application
Dim doc As Word.Document
startForms = String(256, "x")
Set appWord = GetObject(, "Word.Application") 'Set appWord object variable to running instance of Word.
If Err.Number <> 0 Then
Set appWord = New Word.Application 'If Word isn't open, create a new instance of Word.
End If
Set doc = appWord.Documents.Open("C:\myFolder\MyForm.docx", , True)
With doc
.FormFields("wdStartForms").Result = "" 'Clear anything currently in the form's field
.Bookmarks("wdStartForms").Range.Fields(1).Result.Text = startForms
.Visible = True
.Activate
End With
Set doc = Nothing
Set appWord = Nothing
If you use:
Dim FmFld As FormField, Str1 As String
Str1 = (a long string > 256 characters)
Set FmFld = ActiveDocument.FormFields(1)
FmFld.Result = Str1
You get an error: “String too long” (a ridiculous “design” feature, given that you can do it manually without problems!).
Same if you use:
ActiveDocument.Formfields("Text1").Result = Str1
You can get round this by using:
ActiveDocument.Unprotect
FmFld.Range.Fields(1).Result.Text = Str1
ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True
Or if you're referring to the formfield by name:
ActiveDocument.Unprotect
ActiveDocument.Bookmarks("Text1").Range.Fields(1).Result.Text = Str1
ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True
You could also try passing multiple strings and concatenating them, chopping each string into chunks less than 255 characters.

Regex VBA Match

How can i get the value 81.16 in second msgbox?
Regex get only numeric values from string
Sub Tests()
Const strTest As String = "<td align=""right"">116.83<span class=""up2""></span><br>81.16<span class=""dn2""></span></td>"
RE6 strTest
End Sub
Function RE6(strData As String) As String
Dim RE As Object, REMatches As Object
Set RE = CreateObject("vbscript.regexp")
With RE
' .MultiLine = True
'.Global = False
.Pattern = "\b[\d.]+\b"
End With
Set REMatches = RE.Execute(strData)
MsgBox REMatches(0)
MsgBox REMatches(1) 'getting error here
End Function
First of all, try not to use RegEx to parse any kind of xml. Try using xml parsers or XPath
XPath, the XML Path Language, is a query language for selecting nodes
from an XML document. In addition, XPath may be used to compute values
(e.g., strings, numbers, or Boolean values) from the content of an XML
document.
To solve your problem change
'.Global = False 'Matches only first occurrence
Into
.Global = True 'Matches all occurrences
How to properly parse XML in VBA:
Please note that I had to close your <br /> tag to be valid.
Private Sub XmlTestSub()
On Error GoTo ErrorHandler
Dim xml As MSXML2.DOMDocument60
Dim nodes As MSXML2.IXMLDOMNodeList
Dim node As MSXML2.IXMLDOMNode
yourXmlString = "<td align=""right"">116.83<span class=""up2""></span><br />81.16<span class=""dn2""></span></td>"
Set xml = New MSXML2.DOMDocument60
If (Not xml.LoadXML(yourXmlString)) Then
Err.Raise xml.parseError.ErrorCode, "XmlTestSub", xml.parseError.reason
End If
Set nodes = xml.SelectNodes("/td/text()") 'XPath Query
For Each node In nodes
Debug.Print node.NodeValue
Next node
Done:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " " & Err.Description, vbCritical
Resume Done
End Sub