Regex in VBA to pick out specific patterns - excel

I am working with Macros and VBA for the first time for work, I have some limited python experience.
I am trying to find and pick out all the cheques in bank data from prior periods and assign them the category "Accounts Payable Cheques". However, when I run my code below, only one cell populates and the left are left with nothing, however there should be alot of cells populated.
I am wondering where I am going wrong?
Function trim_all(s) As String
s = Trim(s)
s = Replace(s, " ", " ")
s = Replace(s, " ", " ")
s = Replace(s, " ", " ")
s = Replace(s, " ", " ")
trim_all = Replace(s, " ", " ")
End Function
Public Sub regex()
Dim regexObject As RegExp
Set regexObject = New RegExp
Dim CHQ As Boolean
Dim curr As String
Dim description As String
Range("i2").Activate
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
i = True
Do While i = True
' get values'
account = ActiveCell.Offset(0, -8).Value
curr = ActiveCell.Offset(0, -7).Value
description = trim_all(ActiveCell.Offset(0, -4).Value)
debit = ActiveCell.Offset(0, -3).Value
credit = ActiveCell.Offset(0, -2).Value
'Have to define the regex pattern as a string
Dim regexPattern As String: regexPattern = "{chq|cheque|^\d{10}$|^\d{5}$}"
'Quick check that the regex pattern is not empty (maybe supply the pattern as a function in the future?)
If regexPattern <> "" Then
'Set flags and pattern--very similar to how it's done in Python
With regexObject
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = regexPattern
End With
'Test the regex; if it matches then set CHQ=True, otherwise CHQ=False
If regexObject.Test(description) Then
CHQ = True
Else
CHQ = False
End If
End If
'Accounts Payable Cheques - Categorization'
If CHQ = True And curr = "CAD" Then
ActiveCell.Value = "Accounts Payable Cheques, CAD"
ElseIf CHQ = True And curr = "USD" Then
ActiveCell.Value = ""
End If
' continue?'
next_line = ActiveCell.Offset(1, -7).Value
If next_line = "" Then
i = False
Else
' go down 1 cell
ActiveCell.Offset(1, 0).Activate
End If
Loop
Application.Calculation = xlCalculationAutomatic
Application.Calculate
Application.ScreenUpdating = True
MsgBox ("Regex check done!")
End Sub

Related

Return newly generated cell value in MsgBox

Whenever I run this code, it generates a sequential number.
I want to display the new sequential number in a MsgBox, but it prints the older sequential number.
Private Sub ToggleButton1_Click()
Dim reponse As VbMsgBoxResult
Dim REVISIONRNCAUTO As Workbook
Dim Sheet2 As Worksheet
Dim cell_value As String
Set REVISIONRNCAUTO = ActiveWorkbook
Set Sheet2 = REVISIONCRNAUTO.Worksheets(2)
cell_value = Sheet2.Cells(4, "A").Value & Sheet2.Cells(4, "B").Value
If CheckBox1.Value = True And CheckBox4.Value = True And CheckBox7.Value = True And CheckBox2.Value = False And CheckBox3.Value = False _
And CheckBox6.Value = False And CheckBox5.Value = False And CheckBox8.Value = False And CheckBox9.Value = False And CheckBox10.Value = False And CheckBox11.Value = False And CheckBox12.Value = False _
And CheckBox13.Value = False And CheckBox14.Value = False And CheckBox15.Value = False Then
Sheet2.Activate
reponse = MsgBox("Êtes-vous sûr de vouloir générer ce RNC?", vbYesNo + vbQuestion, "Enregistrement RNC")
If reponse = vbYes Then
Sheets("Sheet2").Range("B4").Select
ActiveCell.EntireRow.Insert shift:=xlDown
Sheets("Sheet2").Range("B4:E4").Select
Selection.Borders.Weight = xlThin
Sheets("Sheet2").Range("B4").Select
ActiveCell.Value = "=b5+1"
Sheets("Sheet2").Range("A4").Select
Selection.Borders.Weight = xlThin
ActiveCell.Value = "E"
Else
Exit Sub
End If
End If
MsgBox ("Le nouveau RNC enregistré est le : " & cell_value)
You aren't changing the value of cell_value after you set it.
They are not linked forever like an Excel formula. You have to set it again once you change the cells that it is based on.
Put the cell_value = line right before the Else in addition to where it currently is.

Macro Optimization ifs seem to slow it down a lat

I would love to optimize this code so that it executes faster...
Sub gotocfstatement()
If ActiveCell.Row < 10 Then Exit Sub
If ActiveCell.Row > 5001 Then Exit Sub
If Sheet1.Range("p" & (ActiveCell.Row)).Value = "" Then Exit Sub
Application.ScreenUpdating = False
Application.DisplayStatusBar = False
Filename = Sheet1.Range("p" & (ActiveCell.Row)).Value
Sheet2.Range("b9").Value = Filename
If Sheet2.Range("b15").Value = "" Then
Sheet2.Range("b14").Value = Sheet2.Range("s1").Value
Else
Sheet2.Range("b14").Value = Sheet2.Range("b15").Value
End If
If Sheet2.Range("a81").Value = "" Then
Sheet2.Range("a85").Value = Sheet2.Range("ab1").Value
Else
Sheet2.Range("a85").Value = Sheet2.Range("a81").Value
End If
Sheets("cash flow statement").Select
Application.ScreenUpdating = True
Application.DisplayStatusBar = True
End Sub

Create vba loop to index checkbox and columns

Could someone please point me in the right direction?
View the following code, instead of repetitive lines, I want to loop this to save time...
'show/hide SN# DEFECTIVE
If CheckBox2.Value = True Then Columns("f").EntireColumn.Hidden = False
If CheckBox2.Value = False Then Columns("f").EntireColumn.Hidden = True
'show/hide SN# INSTALLED
If CheckBox3.Value = True Then Columns("g").EntireColumn.Hidden = False
If CheckBox3.Value = False Then Columns("g").EntireColumn.Hidden = True
'show/hide SN# DESCRIPTION
If CheckBox4.Value = True Then Columns("h").EntireColumn.Hidden = False
If CheckBox4.Value = False Then Columns("h").EntireColumn.Hidden = True
'show/hide SN# DESCRIPTION
If CheckBox4.Value = True Then Columns("h").EntireColumn.Hidden = False
If CheckBox4.Value = False Then Columns("h").EntireColumn.Hidden = True
I have the following, which works great...
For i = 2 To 4
chk = Me.Controls("checkbox" & i).Value
MsgBox "checkbox " & i & " " & chk
If chk = False Then
Columns("f").EntireColumn.Hidden = True
Else
Columns("f").EntireColumn.Hidden = False
End If
Next i
However, I also want to index the columns as well, but these are identified as "letters", so how can I also increment an "f" to the next letter "g", and so on...
I wouldn't use loop for this unless you have many more columns to change visibility.
However, what I would do is definitely avoid Ifs and simply use the associate checkboxes' value's opposite to be set as the hidden property value like below. More readable, maintainable and of course shorter.
Columns("f").EntireColumn.Hidden = Not CheckBox2.Value
Columns("g").EntireColumn.Hidden = Not CheckBox3.Value
Columns("h").EntireColumn.Hidden = Not CheckBox4.Value
EDIT: I don't recommend this but to provide you an answer for your question in your way: use Chr function to return letters.
For i = 2 To 4
chk = Me.Controls("checkbox" & i).Value
MsgBox "checkbox " & i & " " & chk
If chk = False Then
Columns(chr(100+i)).EntireColumn.Hidden = True
Else
Columns(chr(100+i)).EntireColumn.Hidden = False
End If
Next i
even shorter using my way:
For i = 2 To 4
Columns(chr(100+i)).EntireColumn.Hidden = Not Me.Controls("checkbox" & i).Value
Next i

excel 2010 vba error calling module

In the below excel 2010 vba all the text files are opened and read by the loop and then a call to a module that is in the same sheet is made. However I am getting an Argument not optional' error on that line (Call CreateXLSXFiles`). I need some expert help in fixing this as I can not figure it out. Thank you :)
VBA
'CREATE REPORT '
MsgBox ("Please click ok to generate analysis reports, vbOKOnly")
Dim myDir As String, fn As String
myDir = "C:\Users\cmccabe\Desktop\EmArray\"
fn = Dir(myDir & "*.txt")
Do While fn <> ""
CreateXLSXFiles myDir & fn
fn = Dir
Loop
Call CreateXLSXFiles
Module
Sub CreateXLSXFiles(fn As String)
' PARSE TEXT FILE AND CREATE XLSX REPORT '
Dim txt As String, m As Object, n As Long, fp As String
Dim i As Long, x, temp, ub As Long, myList
myList = Array("Display Name", "Medical Record", "Date of Birth", _
"Order Date", "Gender", "Barcode", "Sample", "Build", _
"SpikeIn", "Location", "Control Gender", "Quality")
fp = "C:\Users\cmccabe\Desktop\EmArray\"
With Worksheets(1)
.Cells.Clear
.Name = CreateObject("Scripting.FileSystemObject").GetBaseName(fn)
On Error Resume Next
n = FileLen(fn)
If Err Then
MsgBox "Something wrong with " & fn
Exit Sub
End If
On Error GoTo 0
n = 0
txt = CreateObject("Scripting.FileSystemObject").OpenTextFile(fn).ReadAll
With CreateObject("VBScript.RegExp")
.Global = True: .MultiLine = True
For i = 0 To UBound(myList)
.Pattern = "^#(" & myList(i) & " = (.*))"
If .Test(txt) Then
n = n + 1
Sheets(1).Cells(n, 1).Resize(, 2).Value = _
Array(.Execute(txt)(0).submatches(0), .Execute(txt)(0).submatches(1))
End If
Next
.Pattern = "^[^#\r\n](.*[\r\n]+.+)+"
x = Split(.Execute(txt)(0), vbCrLf)
.Pattern = "(\t| {2,})"
temp = Split(.Replace(x(0), Chr(2)), Chr(2))
n = n + 1
For i = 0 To UBound(temp)
Sheets(1).Cells(n, i + 1).Value = temp(i)
Next
ub = UBound(temp)
.Pattern = "((\t| {2,})| (?=(\d|"")))"
For i = 1 To UBound(x)
temp = Split(.Replace(x(i), Chr(2)), Chr(2))
n = n + 1
Sheets(1).Cells(n, 1).Resize(, ub).Value = temp
Next
End With
.Copy
Application.DisplayAlerts = False
With ActiveSheet
.Columns.AutoFit
.Range("B1:B12").ClearContents
End With
ActiveWorkbook.SaveAs Filename:=fp & .Name, _
FileFormat:=xlOpenXMLWorkbook
ActiveWorkbook.Close False
End Sub
The method CreateXLSXFiles takes a String as input :
Sub CreateXLSXFiles(fn As String)
However, you're calling it without passing any string:
Call CreateXLSXFiles
In order to make it work, you need to pass the needed fn (that I guess it means "file name") :
Call CreateXLSXFiles(fn)
or with the newest syntax, simply:
CreateXLSXFiles fn

Excel VBA Sentence Case Funtion Needs Fine Tuning

Below is a function built by others that changes text into sentence case (first letter of each sentence capitalized). The function works nicely except it doesn't capitalize the first letter of the first word. Another issue is that if a sentence is entered in all caps, the function does nothing. I'm looking for some assistance in tweaking the function to correct these issues.
Option Explicit
Function ProperCaps(strIn As String) As String
Dim objRegex As Object
Dim objRegMC As Object
Dim objRegM As Object
Set objRegex = CreateObject("vbscript.regexp")
strIn = LCase$(strIn)
With objRegex
.Global = True
.ignoreCase = True
.Pattern = "(^|[\.\?\!\r\t]\s?)([a-z])"
If .test(strIn) Then
Set objRegMC = .Execute(strIn)
For Each objRegM In objRegMC
Mid$(strIn, objRegM.firstindex + 1, objRegM.Length) = UCase$(objRegM)
Next
End If
End With
ProperCaps = strIn
End Function
Thanks,
Gary
I renamed the function to SentenceCase() and made a few more adjustments:
Public Function SentenceCase(ByVal str As String) As String
Dim regEx As Object, regExM As Object, indx As Object, indxs As Object
Set regEx = CreateObject("VBScript.RegExp")
str = Replace$(str, vbNullChar, vbLf)
str = Replace$(str, vbBack, vbLf)
str = LTrim$(LCase$(str))
With regEx
.IgnoreCase = True
.MultiLine = True
.Global = True
.Pattern = "(^|[\n\f\r\t\v\.\!\?]\s*)(\w)"
If .Test(str) Then
Set indxs = .Execute(str)
For Each indx In indxs
Mid$(str, indx.FirstIndex + 1, indx.Length) = UCase$(indx)
Next
End If
End With
SentenceCase = str
End Function
This is what I tested it with:
MsgBox SentenceCase(" UPPER CASE SENTENCE." & _
vbCrLf & "next line!nEXT sENTENCE" & _
vbCr & "cr ! lower case" & _
vbLf & "lf .new sentence" & _
vbNullChar & " null?null char" & _
vbNullString & "nullString spaces" & _
vbTab & "TAB CHAR.ttt" & _
vbBack & "back? back char" & _
vbFormFeed & "ff ff words" & _
vbVerticalTab & "vertical tab.| lower .case words")
Results:
You can find more details here: Microsoft - Regular Expressions
Paul thank you for taking the time to help. I gave up and searched the net some more found a workable sub, received help from another bulletin board and came up with the following:
Sub SentenceCase(rng As Range)
Dim V As Variant
Dim s As String
Dim Start As Boolean
Dim i As Long
Dim ch As String
Application.ScreenUpdating = False
Application.EnableEvents = False
ActiveSheet.Unprotect
With rng
V = .Value
If IsDate(V) Or IsNumeric(V) Then Exit Sub
s = CStr(V)
Start = True
For i = 1 To Len(s)
ch = Mid$(s, i, 1)
Select Case ch
Case "."
Start = True
Case "?"
Start = True
Case "!"
Start = True
Case "a" To "z"
If Start Then ch = UCase$(ch)
Start = False
Case "A" To "Z"
If Start Then
Start = False
Else
ch = LCase$(ch)
End If
End Select
Mid$(s, i, 1) = ch
Next i
.Value = s
End With
ActiveSheet.Protect
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
This code is doing what I needed. Again thank you for your help.
Gary

Resources