My code:
Public Sub splitUpRegexPattern()
Dim regEx As New RegExp
Dim strPattern As String
Dim strInput As String
Dim strReplace As String
Dim Myrange As Range
Set Myrange = ActiveSheet.Range("B2:B4279")
For Each c In Myrange
strPattern = "([A-Z]{2}\/[A-Z]{2}\/[A-Z][0-9]{2}\/[a-z]{3}[0-9]{9}\/)([0-9]{4})"
If strPattern <> "" Then
strInput = c.Value
strReplace = "$1"
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = strPattern
End With
If regEx.test(strInput) Then
c.Offset(0, 1) = regEx.Replace(strInput, "$2")
Else
c.Offset(0, 1) = ""
End If
End If
Next
End Sub
It was initially working well, it would give me an error, but still complete the task it was doing. But when I use this macro on a new spreadsheet, it gives me the error:
Compile Error: Method or Data Member not found.
All the solutions on this site are tailored to different situations, so I couldn't apply them to my circumstance unfortunately.
I have no idea why this is happening, as I haven't changed any of the code. I am sure if I had a greater understanding with VBA script that I would be able to understand this, but I do not, so I came to find out if someone here could help me!
Thanks!
Aydan
You need to add a reference to a library called "Microsoft VBScript Regular Expressions 5.5" to make it work.
If this code works in a workbook that simply means you have added that library reference and when you copy the code to a new workbook there you will need to add the same reference again.
In the existing code you are auto instantiating the variable called redEx which assumes that the library reference has been already added to make it work properly.
To avoid this, you may use the late binding technique which will not require you to add the reference and the code will work on any workbook.
To do so declare the regEx variable as an Object like below...
Dim regEx As Object
Set regEx = CreateObject("VBScript.RegExp")
My best guess is that you've lost a reference to a library. In VBE, select Tools - References. Find Microsoft VBScript Regular Expressions 5.5 and tick it.
Related
I am stuck - I feel I have checked everything multiple times but I need some pair of fresh eyes on this one:
Sub shopNumConvert()
Call settings
Dim SearchString As String
Dim ReplaceString As String
Dim InputString As String
Dim ShopRange As Range
'Dim RegEx As New RegExp
Dim RegEx As RegExp
SearchString = "[^a-z]{2}"
ReplaceString = "0\\1"
Set ShopRange = DataWs.Range("G2:G10")
Set RegEx = New RegExp
For Each cell In ShopRange
If SearchString <> "" Then
InputString = cell.Value
With RegEx
.Global = True
.IgnoreCase = False
.MultiLine = True
.Pattern = SearchString
End With
If RegEx.Test(InputString) Then
ShopRange.Value = (RegEx.Replace(InputString, ReplaceString))
End If
End If
Next
Set RegEx = Nothing
End Sub
Why do I get the error message Object variable or With block variable not set
In settings() I have defined which sheet 'DataWs' is
Help is much appreciated!
Thank you for your comments (and good practice advise - not working with VBA frequently so I am learning on the go)!
The problem was indeed with DataWs and I had to change something in settings() - the code as posted now runs without throwing an error - I will however look at a few of your comments and see how to incorporate those for improving the code.
Best,
Janine
I get assignments in emails that come to a shared Outlook mailbox.
In a typical email there are multiple strings and variables regarding a client, including their name, date and ID with a hyphen that I also want to get rid of.
There are two types of IDs. Both consist of 8 numbers and a hyphen, e.g. 1234567-8 and 123456-78. Sometimes there is a character in front of the number so I believe storing data in string is a must. I want to make several copies of the macro for each type of data. I want it all in a simple string form as I want to copy it to clipboard and paste elsewhere and have no need to process it further.
The code below does all I want except it stores the data in variables instead of string and does not remove the hyphen.
Code courtesy of vbaexpress' gmayor.
Option Explicit
Sub GetCustomer()
Dim olItem As Outlook.MailItem
Dim olInsp As Outlook.Inspector
Dim dCust As DataObject
Dim wdDoc As Object
Dim oRng As Object
Dim sCustomer As String
Dim bFound As Boolean
On Error GoTo lbl_Exit
Set olItem = ActiveExplorer.Selection.Item(1)
With olItem
Set olInsp = .GetInspector
Set wdDoc = olInsp.WordEditor
Set oRng = wdDoc.Range
With oRng.Find
Do While .Execute(findText:="Customer #:[ 0-9]{2,}", MatchWildcards:=True)
sCustomer = Trim(Split(oRng.Text, Chr(58))(1))
bFound = True
Set dCust = New DataObject
dCust.SetText sCustomer
dCust.PutInClipboard
MsgBox "Customer number '" & sCustomer & "' copied to clipboard"
Exit Do
Loop
End With
If Not bFound Then MsgBox "Customer number not found"
End With
lbl_Exit:
Set olItem = Nothing
Set olInsp = Nothing
Set wdDoc = Nothing
Set oRng = Nothing
Set dCust = Nothing
Exit Sub
End Sub
I want to search the currently previewed email (if that is possible), without actually opening it in another separate window, for a phrase like
"Customer ID: 123456-78"
and reformat the last part by simply removing the hyphen and disregarding the first part
"Customer ID: "
(there is a giant space between the Customer ID and the number).
I also want to reformat the date from 11.22.2019 to 2019-22-11 and also copy it to clipboard.
Searches based on wildcards are limited to what wildcards can provide, which is better than nothing, but still not very much.
Outlook uses Word functions for this, so that the VBA documentation for Word applies. Applicable wildcards themselves are can be seen using the "Special" button in the "Find" dialog (F4 in Outlook), after "use wildcards" has been checked.
To my knowledge there is no concept of "optional" parts in wildcard searches, which means you need to try more than one wildcard pattern to cover your "sometimes there is a letter in front" case.
So the general approach, based this knowledge and on your sample code, would be
Pick the currently selected MailItem in the ActiveExplorer
For each predefined wildcard pattern
reset the search range to the whole email
execute wildcard search
as long as there are search hits
display result, let user pick or cancel the search
This way multiple patterns can be defined and you have a chance to continue to the next hit if the first hit is a false positive.
I found the pattern [0-9-]{8;9} plus MatchWholeWord to work reasonably well (blocks of digits and dashes, between 8 or 9 characters long), but real life data often has surprises. You will probably need to add more patterns. Watch out: for me, Outlook wants ; instead of ,. This might be dependent on the system locale, I'm not sure.
Also I'm not a fan of a "silent" On Error Resume. If there is an error, I prefer to see an error actual message. If there is a condition that can be checked in order to prevent an error, I prefer to check for this condition explicitly. This makes the code more robust and debugging easier. My Sub does not contain an On Error line for that reason.
In code, this would look like this:
Sub GetCustomer()
Dim olItem As Outlook.MailItem
Dim oRng As Object
Dim sCustomer As String
Dim patterns As Variant, pattern As Variant
Dim answer As VbMsgBoxResult
' bail out if the preconditions are not right
If ActiveExplorer.Selection.Count = 0 Then Exit Sub
If Not (TypeOf ActiveExplorer.Selection.item(1) Is MailItem) Then Exit Sub
Set olItem = ActiveExplorer.Selection.item(1)
Set oRng = olItem.GetInspector.WordEditor.Range
' add more wildcard patterns in descending order of likelyhood
patterns = Array("[0-9-]{8;9}", "[A-Z][0-9-]{8;9}")
For Each pattern In patterns
oRng.WholeStory
While oRng.Find.Execute(findText:=pattern, MatchWildcards:=True, MatchWholeWord:=True)
answer = MsgBox(oRng.Text, vbYesNoCancel + vbQuestion, "Customer Number")
If answer = vbYes Then
With New DataObject
.SetText oRng.Text
.PutInClipboard
End With
Exit For
ElseIf answer = vbCancel Then
Exit For
End If
Wend
Next pattern
End Sub
Setting variables to Nothing at the end of the function is superfluous.
I have got following codes from this microsoft page.
https://msdn.microsoft.com/en-us/library/e9waz863(v=vs.90).aspx
' Add Option Strict Off to the top of your program.
Option Strict Off
.
Private Sub getExcel()
Dim fileName As String = "c:\vb\test.xls"
If Not My.Computer.FileSystem.FileExists(fileName) Then
MsgBox(fileName & " does not exist")
Exit Sub
End If
' Set the object variable to refer to the file you want to use.
Dim excelObj As Object = GetObject(fileName)
' Show Excel through its Application property.
excelObj.Application.Visible = True
' Show the window containing the file.
Dim winCount As Integer = excelObj.Parent.Windows.Count()
excelObj.Parent.Windows(winCount).Visible = True
' Insert additional code to manipulate the test.xls file here.
' ...
excelObj = Nothing
End Sub
Everything is okey when Option Strict Off
Everything is not okey when Option Strict On
So, how to solve that errors when Option Strict On?
Be careful! I want to get specific excel file from the same excel instance.
+1 for striving to use Option Strict On. :)
However, the code is using what is known as Late Binding and that requires you have Option Strict Off. You can however, minimize the scope of Option Strict Off by creating a new code file and using a Partial Class definition to contain the code that needs Late Binding.
You might be able to get by using the VB CallByName function with Option Strict On, but that would get ugly real quick and probably be very slow.
There also is an advanced technique using native API's that is called COM reflection that should work with Option Strict On. This technique is described in the article: [Basic Instincts - Inspecting COM Objects with Reflection].(https://msdn.microsoft.com/en-us/magazine/dd347981.aspx).
The typical method for early binding (Option Strict On) is to add a reference to the Excel primary interop assembly. This technique has some detractors as well, but is by far the easiest method.
Edit: The following demonstrates how to use the Excel PIA's and early binding to open a workbook directly similar to the OP's original code.
Dim wbPath As String = "*** replace with path to your workbook ***"
Dim wb As Excel.Workbook = CType(GetObject(wbPath), Excel.Workbook)
'or
'Dim wb As Excel.Workbook = CType(Marshal.BindToMoniker(wbPath), Excel.Workbook)
Dim app As Excel.Application = wb.Application
app.Visible = True
wb.Windows(1).Visible = True
As a side note, there is no need to depend on the Interop.Excel early binding, if you know that it works. You can change the Error Notifications to Warning and still compile and run.
' Imports Microsoft.Office.Interop.Excel
Dim fileName = "c:\vb\test.xls"
If Not IO.File.Exists(fileName) Then MsgBox(fileName & " does not exist") : Exit Sub
Dim obj = GetObject(fileName, "Excel.Application")
Dim wb = TryCast(obj, Workbook)
wb.Application.Visible = True
wb.Windows(1).Visible = True
I've written a pretty useful macro within Excel in VBA and am attempting to transfer it to a stand-alone windows application written in VB.net. I've found all the referencing pretty confusing and am now facing trouble in converting the general syntax of my code.
I'm pasting below the relevant code:
Dim ElevenSheets As Excel.Worksheet
Dim TwelveSheets As Excel.Worksheet
Dim ThirteenSheets As Excel.Worksheet
Dim WorkingSheet As Excel.Worksheet
Dim xlApp As Excel.Application
Dim xlWorkBook As Excel.Workbook
xlApp = New Excel.Application
xlWorkBook = xlApp.Workbooks.Open("FILENAME.xls") 'Removed file name for company confidentiality purposes.
ElevenSheets = xlWorkBook.Worksheets("2011")
TwelveSheets = xlWorkBook.Worksheets("2012")
ThirteenSheets = xlWorkBook.Worksheets("2013")
WorkingSheet = xlWorkBook.Worksheets("WorkingSheet")
...
Cell = WorkingSheet.Range("B3") '<--- This line causes the error.
CurrentCell = (Cell.Row & "," & Cell.Column)
CurrentRow = Cell.Row
MyColumn = (Cell.Column)
CurrentCell = (CurrentRow & "," & MyColumn)
So, as you can see I've pointed out the line that gives me an error. I'm trying to set a range names "Cell" and the error "MissingMemberException unhandled No default member found for type 'DBNull'" presents itself.
Does anyone know what I've done wrong? I'm sure it's something very simple with my syntax but am finding this whole process difficult and also finding it difficult to understand other reasonably similar topics on the internet.
Thanks for bothering to ready this and let me know if you need more context,
Josh
I dont see any constructor for Cell. Also you dont have to explicitly declare all those worksheets. You can simply call them using something like xlWorkBook("WorkingSheet").Range("B3")
I have fixed the problem through trial and error. The way I did it was simply change these declarations:
ElevenSheets = xlWorkBook.Worksheets("2011")
TwelveSheets = xlWorkBook.Worksheets("2012")
ThirteenSheets = xlWorkBook.Worksheets("2013")
WorkingSheet = xlWorkBook.Worksheets("WorkingSheet")
To this:
ElevenSheets = CType(xlWorkBook.Worksheets(1), Excel.Worksheet)
TwelveSheets = CType(xlWorkBook.Worksheets(2), Excel.Worksheet)
ThirteenSheets = CType(xlWorkBook.Worksheets(3), Excel.Worksheet)
WorkingSheet = CType(xlWorkBook.Worksheets(4), Excel.Worksheet)
I don't know whether changing the sheet names to the sheet number fixed it or the CType fixed it. But one of them did.
Thank-you for your contributions!
I am trying to reference newly added Worksheet by it's CodeName property. The problem is that CodeName returns empty string unless run from debugger.
Set tableSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
MsgBox tableSheet.CodeName
Even this simple example doesn't work unless I put a break point on MsgBox line.
What is the problem with this?
I was able to duplicate your issue. Some googling revealed this answer:
Sub test()
Dim tablesheet As Excel.Worksheet
Set tablesheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
MsgBox ThisWorkbook.VBProject.VBComponents(tablesheet.Name).Properties("Codename")
End Sub
I think you have to check Microsoft Visual Basic for Applications Extensibility 5.3 in Tools>References.
I also needed to read codename for new sheet. This solution worked for me:
Go to Trust Center, under Macro settings check "Trust access to VBA project model".
Now just put this three lines before the line where you need code name. It won't work without this. It is a VBA quirk.
On Error Resume Next
Debug.Print ActiveWorkbook.VBProject.VBComponents(Worksheets(ActiveSheet.Name).CodeName).Properties("Codename")
On Error GoTo 0
Now use your code name like this:
strActiveSheetCodeName = ActiveWorkbook.VBProject.VBComponents(Worksheets(ActiveSheet.Name).CodeName).Properties("Codename")
I can confirm this behavior. I have never used CodeName before, I use sometimes Name to reference a sheet.
Sub Test()
Dim tableSheet As New Worksheet
Set tableSheet = Worksheets.Add(After:=Worksheets(Worksheets.Count))
MsgBox tableSheet.Name
End Sub
This gives the name of the sheet in the MsgBox and it is not only readable, you can change the name of the sheet if you want.
I have a similar problem for a new sheet that created by macro (it would have a blank codename unless you open the Macro Editor).
For my case, since I need the code name to insert some macro to the new sheet. So I use the following code, and it works. It seems the codeName would have value, due to my code access Name attribute of 'VBComponents.item', which is codeName attribute for sheet.
Note: I am not sure why, below code would open the VBA Editor automatically.
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Set VBProj = ActiveWorkbook.VBProject
Dim i
For i = 1 To VBProj.VBComponents.Count
If VBProj.VBComponents.Item(i).Name = ActiveSheet.CodeName Then
Set VBComp = VBProj.VBComponents.Item(i)
End If
Next