Vba excel. Find text insie cell with line break - vba

I have the following code. It searches one column for a specific value. It works fine, but if the cell have line break, the code does not search the second line.
vardestinolinha = ThisWorkbook.Sheets("base").Range("a11").End(xlDown).Row
a = 10
k = a
For i = a To vardestinolinha
Search = ThisWorkbook.Sheets(NomeTabela).Range("a2")
Replacement = ThisWorkbook.Sheets(NomeTabela).Range("c" & i)
varposicao = ThisWorkbook.Sheets(NomeTabela).Range("b" & i) '''''
Set rngFind = ThisWorkbook.Sheets("base").Columns(2).Find(What:=Search, LookIn:=xlValues, lookat:=xlPart)
Do While Not rngFind Is Nothing
tamanho = Len(rngFind)
p = InStr(1, rngFind, Search, vbTextCompare)
If p > 0 Then
ThisWorkbook.Sheets("base").Cells(k, 5) = ThisWorkbook.Sheets("base").Cells(k, 3)
k = k + 1
End If
Set rngFind = ThisWorkbook.Sheets("base").Columns(2).FindNext
Loop
k = i + 1
Next
I want the code to search an entire cell even when there are line breaks.

If the text was entered in the cell useing the Alt+Enter method you can use this in your VBA:
" & Chr(10) & "
Here is the .Find method that I have used.
Private Sub CommandButton1_Click()
Set RngClosedDate = Range("A1:Z10").Find(What:="Closed" & Chr(10) & "(Date)", LookAt:=xlWhole, LookIn:=xlValues)
' If the text that is searched for from the line above is not found then a message box is displayed and sub function is exitied
If RngClosedDate Is Nothing Then
MsgBox "Closed (Date) Column Header Not found. Cannot sort or format records."
Exit Sub
End If
End Sub

Related

VBA Word. How to find first empty cell in Word table?

I've been trying to find the first empty cell in Word table using VBA.
The code which I've put below finds all the empty cells instead I want to find the first one after filled one. How to solve this problem?
For Each oRow In Selection.Tables(1).Rows
For Each oCell In oRow.Cells
If Selection.Text = Chr(13) & Chr(7) Then
oCell.Select
'Selection.PasteSpecial DataType:=wdPasteText
MsgBox oCell.RowIndex & " " & oCell.ColumnIndex & " is empty."
End If
Next oCell
Next oRow
Is this what you had in mind?
Sub FindNextBlank()
Dim Tbl As Table
Dim TblRow As Row
Dim HasText As Boolean
Dim LookForText As Boolean, Done As Boolean
Dim R As Long, C As Long
Dim Txt As String
LookForText = True
With ThisDocument.Tables(1)
For R = 1 To .Rows.Count
Set TblRow = .Rows(R)
For C = 1 To TblRow.Cells.Count
HasText = (Len(TblRow.Cells(C).Range.Text) > 2)
If HasText = LookForText Then
If LookForText Then
LookForText = Not LookForText
Else
Done = True
TblRow.Cells(C).Range.Select
Exit For
End If
End If
Next C
If Done Then Exit For
Next R
If Done Then
Txt = "Cell #" & C & " in row " & R & " is free."
Else
Txt = "No free cell was found that" & vbCr & _
" follows one that has text."""
End If
End With
MsgBox Txt, vbInformation, "Search result"
End Sub
For ... Each is faster but I instinctively distrust it because the sequence of items in them is usually determined by the sequence of their creation. That may or may not be top to bottom, left to right. Calling cells by their coordinates may take a little longer but you retain control of the sequence.
As you may have discovered, determining an empty cell in Word is not as straightforward as it might appear. The code below looks for the first cell where the length of the text in the cell is 1 after removing any spaces, tabs and vbCr. You might extend this to also look for vbLF, manual line breaks and other characters that might be in a cell but not visible if you have view text markers turned off.
The .Cells method of a table range is the most appropriate tool to use here because it will work even if the table has merged cells. Searching a table using the cell coordinates will fail if there are merged cells in the table. Using the .Cells method the table is searched from Top Left to Bottom right (row by column).
Option Explicit
Sub Test()
Dim myCell As Word.Range
Set myCell = FirstEmptyCell(ActiveDocument.Tables(1).Range)
myCell.Select
End Sub
' Returns the first cell that has a text length of 1
' after removing spaces and tab characters from the cell text
Public Function FirstEmptyCell(ByVal TableRange As Word.Range) As Word.Range
Dim myCell As Word.Cell
For Each myCell In TableRange.Tables(1).Range.Cells
Dim CellText As String
CellText = myCell.Range.Text
CellText = Replace(CellText, vbTab, vbNullString)
CellText = Replace(CellText, " ", vbNullString)
CellText = Replace(CellText, vbCr, vbNullString)
If Len(CellText) = 1 Then
Set FirstEmptyCell = myCell.Range
Exit Function
End If
Next
End Function
The solution is really much simpler than the other 'answers' suggest:
Dim i As Long
With Selection
If .Information(wdWithInTable) = True Then
With .Tables(1).Range
For i = 1 To .Cells.Count
With .Cells(i)
If Len(.Range.Text) = 2 Then
MsgBox " Row " & .RowIndex & ", Column " & .ColumnIndex & " is empty."
.Range.PasteSpecial DataType:=wdPasteText
Exit For
End If
End With
Next
End With
Else
MsgBox "No table selected", vbExclamation
End If
End With
I've even added some error checking.

Using .Find() to find specific text in column

I'm having trouble making sure that my code uses what the end user inputs to find a set of data pertaining to that value and continues with the code there. For example, if the user were to input "V-" as the prefix to the tag number, in theory cell A7 should be selected after the code is complete. However, the code proceeds to run line "MsgBox "No blank cell was found below a tag number with prefix " & str & ".", vbExclamation" and select cell A3 due to the fact that it contains "V-" in the cell. I tried changing the Matchcase to true but it did not help. I also do not want the entered value to be case sensitive.
Code being used:
Private Sub Worksheet_Activate()
Dim msg As String
Dim Cell As Range
Dim str As String, firstcell As String
msg = "Would you like to find the next available tag number?"
result = MsgBox(msg, vbYesNo)
If result = vbYes Then
str = Application.InputBox("Enter The Tag Number Prefix ", "Prefix To Tag Number")
If str = "" Then Exit Sub
If Right(str, 1) <> "-" Then str = str & "-"
With Range("A:A")
Set Cell = .Find(str, lookat:=xlPart, MatchCase:=False)
If Not Cell Is Nothing Then
firstcell = Cell.Address
Do
If Cell.Offset(1, 0) = "" Then
Cell.Offset(1, 0).Select
Exit Sub
ElseIf InStr(LCase(Cell.Offset(1, 0)), LCase(str)) = 0 Then
Cell.Select
MsgBox "No blank cell was found below a tag number with prefix " & str & ".", vbExclamation
Exit Sub
End If
Set Cell = .FindNext(Cell)
Loop While Not Cell Is Nothing And firstcell <> Cell.Address
End If
End With
Else
Cancel = True
End If
End Sub
If you want to find cells whose content begins with (e.g.) "V-" then
Set Cell = .Find(str & "*", lookat:=xlWhole, MatchCase:=False)
For the data below:
Sub tester()
With ActiveSheet.Columns(1)
Debug.Print .Find("C-" & "*", lookat:=xlWhole, _
MatchCase:=False).Address() '>> $A$3
Debug.Print .Find("V-" & "*", lookat:=xlWhole, _
MatchCase:=False).Address() '>> $A$5
End With
End Sub

Excel VBA: FindNext in nested loops

I am trying to create a loop using the .Find function within another loop which is already using .Find. I want to search for strings that I have saved in an array.
For example, these are the string values saved in the array strItem in Sheet1.
"unit1", "unit2", "unit3"
I would like to search them one by one from Sheet2. Sheet2 looks like this:
unit1
unit2
unit3
unit1.pdf
text1
subject1
subject2
subject3
text2
=========
unit2.pdf
text1
subject1
subject2
subject3
text2
=========
unit3.pdf
text1
subject1
subject2
subject3
text2
=========
After searching for "unit1.pdf", I search all cells below it for "subject", and get cell values of subject1, 2, and 3. The search for "subject" cells should stop at the next cell which contains "====".
Next I search for "unit2", and if found search for "subject" cells under it as before. Again, stop at the cell containing "====". And so on.
In my code, what I am trying to do was
Search for the string "unit".
Use its .row as the range to start searching for "subject".
Return all subjects until the cell contains "====". This is a part of my code that I can't really make to work.
Code:
Wb2.Sheets("Sheet2").Activate
With Wb2.Sheets("Sheet2").Range("A1:A1048575")
For Each strItem In arrExcelValues
myStr = strItem & ".pdf"
Set p = .Find(What:=myStr, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False)
If Not p Is Nothing Then
firstAddress = p.Address
Do
myStr2 = p.row
strStart = "A" & myStr2
strEnd = "A1048575"
With Wb2.Sheets("Sheet2").Range(strStart, strEnd)
Set p1 = .Find(What:="Subject", LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False)
If Not p1 Is Nothing Then
firstAddress = p1.Address
Do
myStr2 = myStr2 + 1
If p1.Offset(myStr2, 0).Value = "====" Then
Exit Do
Else
MsgBox p1.Value & strItem
End If
Set p1 = .FindNext(p1)
Loop While Not p1 Is Nothing And p1.Address <> firstAddress
Else
MsgBox "Not found"
End If
End With
Set p = .FindNext(p)
Loop While Not p Is Nothing And p.Address <> firstAddress
Else
MsgBox "Not found"
End If
Next
End With
You're not far off, but there are a couple of things to think about:
It seems you know the order of your data, you can use this to make life easier than using Find on the entire column.
You cannot use nested With statements unless you are going further into the child elements. It is good you are trying to fully qualify things, but be careful. For instance,
' This is okay
With ThisWorkbook.Sheets("Sheet2")
With .Range("A1")
MsbBox .Value
End With
With .Range("A2")
MsgBox .Value
End With
End With
' This is not okay, and present in your code
With ThisWorkbook.Sheets("Sheet2").Range("A1")
MsgBox .Value
With ThisWorkbook.Sheets("Sheet2").Range("A2")
Msgbox .Value
End With
End With
I have taken the ideas in your code, and re-written it to be a bit clearer, and hopefully achieve what you want. See the comments for details:
Dim Wb2 As Workbook
Dim lastRow As Long
Set Wb2 = ThisWorkbook
' Get last used row in sheet, so search isn't on entire column
lastRow = Wb2.Sheets("Sheet2").UsedRange.Rows.Count
' Set up array of "unit" values
Dim arrExcelValues() As String
arrExcelValues = Split("unit1,unit2,unit3", ",")
' Declare variables
Dim pdfCell As Range
Dim eqCell As Range
Dim eqRow As Long
eqRow = 1
Dim subjCell As Range
Dim strItem As Variant
' Loop over unit array
With Wb2.Sheets("Sheet2")
For Each strItem In arrExcelValues
' Find the next "unitX.pdf" cell after the last equals row (equals row starts at 1)
Set pdfCell = .Range("A" & eqRow, "A" & lastRow).Find(what:=strItem & ".pdf", lookat:=xlPart)
If Not pdfCell Is Nothing Then
' pdf row found, find next equals row, store row value or use last row
Set eqCell = .Range("A" & pdfCell.Row, "A" & lastRow).Find(what:="====", lookat:=xlPart)
If eqCell Is Nothing Then
eqRow = lastRow
Else
eqRow = eqCell.Row
End If
' Loop through cells between pdf row and equals row
For Each subjCell In .Range("A" & pdfCell.Row, "A" & eqRow)
' If cell contents contain the word "subject" then do something (display message)
If InStr(UCase(subjCell.Value), "SUBJECT") > 0 Then
MsgBox "Subject: " & subjCell.Value & ", Unit: " & strItem
End If
Next subjCell
Else
MsgBox "Item not found: " & strItem & ".pdf"
End If
Next strItem
End With

Excel VBA macro for one column, if true, apply formula to another column

For context:
I would like for the program to look through column B, identify the first "< / >" (which is purely stylistic and can be changed if necessary - it's only used to break up the data) as the start of a week at cell B9 and the next "< / >" (end of the week) at B16. So the range I'm interested in is B10-B15. It would then sum those numbers from J10 to J15 (Earned column) and paste that sum in L16 (Week Total column). The same could then be done with 'Hours' and 'Week Hours'. For the following week (and thereafter) the 'end of the week' "< / >" becomes the start of the week, and the program continues until B200.
I don't have any experience with VBA and so made the following incomplete attempt (based on what I had found online) but felt too out of my depth not to ask for help.
Sub Work()
Dim rng As Range
Dim rngFound As Range
Set rng = Range("B:B")
Set rngFound = rng.Find("</>")
If rngFound Is "</>" Then
If Cell = "</>" Then
End If
End Sub
Thank you for any help and please let me know if I can be clearer or elaborate on something.
The following code will loop through 200 lines, looking for your symbol. When found, it will sum the numbers in column J for rows between the current row and the last symbol.
I've included two lines that will update the formula. To me, the 2nd one is easier to understand.
Sub Work()
Dim row As Integer
row = 4
Dim topRowToAdd As Integer 'Remember which row is the
'top of the next sum
topRowToAdd = 4
While row <= 200
If Cells(row, 2) = "</>" Then
'Cells(row, 10).FormulaR1C1 = "=SUM(R[" & -(row - topRowToAdd) & "]C[0]:R[" & -1 & "]C[0])"
Cells(row, 10).Value = "=SUM(J" & topRowToAdd & ":J" & row - 1 & ")"
topRowToAdd = row + 1
End If
row = row + 1
Wend
End Sub
Sub Work()
Dim rng As Range, rngFound As Range
Set rng = Range("B:B")
Set rngFound = rng.Find("</>")
If rngFound.Value2 = "</>" Then
'whatever you want to do
End If
End Sub
So at a second glance it looks like this. If you'd like to make it structured you'd need to use a countifs function first.
Sub Work()
Dim rng As Range, rngFound(1) As Range
Set rng = Range("B1:B200")
On Error GoTo Err 'it is quite possible it will run into an error if there are no matches and I'm too lazy for structured solution
Set rngFound(0) = rng.Find(What:="</>", LookAt:=xlWhole, SearchDirection:=xlNext) 'finds the first
Set rngFound(1) = rng.Find(What:="</>", LookAt:=xlWhole, SearchDirection:=xlNext, After:=rngFound(0)) 'finds the first after the first (i.e. the second)
Set rngFound(0) = rngFound(0).Offset(1, 8) '8 is the difference between B and J, row shifts as per description, I advise you to make it a variable
Set rngFound(1) = rngFound(1).Offset(-1, 8)
If rngFound(1).Row > rngFound(0).Row Then 'if it's not higher, then it recurred and found the first range again
rngFound(1).Offset(1, 2).Formula = "=SUM(" & Range(rngFound(0), rngFound(1)).Address & ")" 'L column will have the sum as a formula
Else
MsgBox "There is a single match in " & rng.Address(False, False)
End If
If False Then
Err:
MsgBox "There are no matches in " & rng.Address(False, False)
End If
End Sub
Now for the grand finale:
Sub Work()
Dim rng As Range, rngFound() As Range, rngdiff(1) As Long, rngcount As Long
Set rng = Range("B1:B200")
rngcount = rng.Cells.Count
ReDim rngFound(rngcount)
rngdiff(0) = Range("J1").Column - rng.Column ' the range that needs to be summed is in column J
rngdiff(1) = Range("L1").Column - rng.Column ' the range containing the formula is in column L
On Error GoTo Err 'it is quite possible it will run into an error if there are no matches and I'm too lazy for structured solution
Set rngFound(0) = rng.Find(What:="</>", LookAt:=xlWhole, SearchDirection:=xlNext) 'finds the first
'loop starts
For i = 1 To rngcount
Set rngFound(i) = rng.Find(What:="</>", LookAt:=xlWhole, SearchDirection:=xlNext, After:=rngFound(i - 1)) 'finds the next
If rngFound(i).Row > rngFound(i - 1).Row Then 'if it's not higher, then it recurred and found the first range again
rngFound(i).Offset(0, rngdiff(1)).Formula = "=SUM(" & Range(rngFound(i - 1).Offset(1, rngdiff(0)), rngFound(i).Offset(-1, rngdiff(0))).Address & ")" 'L column will have the sum as a formula
Else
Exit Sub 'if it recurred the deed is done
End If
Next i
If False Then
Err:
MsgBox "There are no matches in " & rng.Address(False, False)
End If
End Sub

check for user input data in dynamically added ComboBoxes

I am using a user form to display the acronyms found in a document and the definitions of the acronyms. Because i won't know in advance how many there will be I have created all of the labels, check boxes and comboBoxes dynamically using the for loop below.
I am now stuck in that I want to allow the user to be able to type in the comboBox a new definition is for example one didn't exist in my excel database or they want to use a different definition to the one that is there (I am aware this is bad practice but unfortunately people don't stick to the standard list). Now that all works fine with it set up as it is however my problem is that I want to check if the user has entered something new or not.
So my question is, is there a built in function or variable that does this? or is there a simple way to do it? (I already have tried and tested the code to add the string to my database so that is not an issue, just the checking if it wasn't there before without running through the entire database from scratch again)
For i = 1 To n
checkBoxi = "CheckBox" & i
labeli = "Label" & i
comboBoxi = "ComboBox" & i
'add checkbox, label and combobox
.MultiPage1.Pages("Page1").Controls.Add "Forms.CheckBox.1", checkBoxi
.MultiPage1.Pages("Page1").Controls.Add "Forms.Label.1", labeli
.MultiPage1.Pages("Page1").Controls.Add "Forms.ComboBox.1", comboBoxi
'position check box
.MultiPage1.Pages("Page1").Controls(checkBoxi).Left = LeftSpacing
.MultiPage1.Pages("Page1").Controls(checkBoxi).Top = TopSpacing + rowHeight * i
'position labels
.MultiPage1.Pages("Page1").Controls(labeli).Left = LeftSpacing + 15
.MultiPage1.Pages("Page1").Controls(labeli).Top = TopSpacing + 2 + rowHeight * i
.MultiPage1.Pages("Page1").Controls(labeli).Caption = acronyms(i - 1)
.MultiPage1.Pages("Page1").Controls(labeli).Width = 70
'position comboBox
.MultiPage1.Pages("Page1").Controls(comboBoxi).Left = LeftSpacing + 100
.MultiPage1.Pages("Page1").Controls(comboBoxi).Top = TopSpacing + rowHeight * i
.MultiPage1.Pages("Page1").Controls(comboBoxi).Width = 300
'find definitions for comboBox
' Find the definition from the Excel document
With objWbk.Sheets("Sheet1")
' Find the range of the cells with data in Excel doc
Set rngSearch = .Range(.Range("A1"), .Range("A" & .rows.Count).End(-4162))
' Search in the found range for the
Set rngFound = rngSearch.Find(What:=acronyms(i - 1), After:=.Range("A1"), LookAt:=1)
' if nothing is found count the number of acronyms without definitions
If rngFound Is Nothing Then
' Set the cell variable in the new table as blank
ReDim targetCellValue(0) As String
targetCellValue(0) = ""
' If a definition is found enter it into the cell variable
Else
targetCellValue(0) = .Cells(rngFound.Row, 2).Value
'MsgBox (targetCellValue(0) & " " & 0)
firstAddress = rngFound.Address
Do Until rngFound Is Nothing
Set rngFound = rngSearch.FindNext(After:=rngFound)
If rngFound.Address = firstAddress Then
Exit Do
ElseIf rngFound.Address <> firstAddress Then
j = j + 1
ReDim Preserve targetCellValue(0 To j) As String
targetCellValue(j) = .Cells(rngFound.Row, 2).Value
'MsgBox (targetCellValue(j) & " " & j)
End If
Loop
End If
End With
Dim k As Integer
For k = 0 To j
.MultiPage1.Pages("Page1").Controls(comboBoxi).AddItem targetCellValue(k)
Next k
j = 0
Next i
I found a way to do it. The value typed in by a user is not automatically included in the comboBox list therefore you can check it against the list to see if it was there before.
code:
For intComboItem = 0 To .MultiPage1.Pages("Page1").Controls(comboBoxi).ListCount - 1
If .MultiPage1.Pages("Page1").Controls(comboBoxi).Value = .MultiPage1.Pages("Page1").Controls(comboBoxi).List(intComboItem) Then
newDef = False
Exit For
Else
newDef = True
End If
Next
If newDef Then
MsgBox ("new def: " & .MultiPage1.Pages("Page1").Controls(comboBoxi).Value)
End If