Excel VBA loop through every row in Textbox multiline - excel

I have a multiline textbox (with enable to press the Enter key), and I want to loop through every line and get the full line text.
Please note that the textbox word wrap is enabled and if the new line created by wrapping it will be similar to new line (chr(10)), In other words, I need to grab every line of text as it display on the screen and it doesn't matter if its a new line that created by pressing the "Enter" key or just the text wrapping created a new line.
I need somthing like this pseudo code:
for each line in textbox
Debug.Pring line
next

The GetLines function creates an array where each element of the array is a line from the TextBox passed into the function. I decided to strip out control characters but if this is not desired you can easily change the logic.
Capturing the GetLines return value allows you to loop through the results:
Option Explicit
Private Sub UserForm_Initialize()
Text1.Text = "This is line 1" & vbNewLine & "This is a long line that will wrap"
End Sub
Private Sub Command1_Click()
Dim lines() As String
Dim line As Variant
lines = GetLines(Text1)
For Each line In lines
Debug.Print line
Next
End Sub
Private Function GetLines(ByVal tb As MSForms.TextBox) As String()
Dim i As Integer
Dim lc As Integer
Dim c As String
Dim lines() As String
tb.SetFocus
lc = 0
ReDim lines(0 To tb.lineCount - 1)
For i = 0 To Len(tb.Text) - 1
tb.SelStart = i
c = Mid(tb.Text, i + 1, 1)
If Asc(c) >= 32 Then lines(lc) = lines(lc) & c
If tb.CurLine > lc Then lc = lc + 1
Next
GetLines = lines
End Function

For the part where the user presses "enter", it's easy enough.
A simple Debug.Print TextBox1.Text should print it as is.
If you want ot do the pseudo code, you could go with
tbText = Split(TextBox1.Text, vbNewLine)
For Each Line In tbText
Debug.Print Line
Next
Both of these however fail to detect the wordwrap.
I got a slightly hacky approach from this question
I used the hidden textbox, to keep the code simpler.
So I created another textbox, named measure, set AutoSize = True, WordWrap = False, Visible = False
and set then font options to the same as the first textbox. And used the following code:
Dim i As Long, w As Double, num As Long, memory As String
w = TextBox1.Width
tbText = Split(TextBox1.Text, vbNewLine)
For Each Line In tbText
measure.Text = Line
If measure.Width > w Then
shorten:
memory = measure.Text
While measure.Width > w
num = InStrRev(measure.Text, " ")
measure.Text = Left(measure.Text, num - 1)
i = Len(memory) - num
Wend
Debug.Print measure.Text
measure.Text = Right(Line, i)
If measure.Width > w Then
GoTo shorten
Else
Debug.Print measure.Text
End If
Else
Debug.Print Line
End If
Next
But feel free to use any of the other methods to get the width of the text for this code, or use an approach from the Link that Tim commented.

Related

VBA Excel Run-time error '438' Object doesn't support this property or method when using with msforms.TextBox

I'm trying to make a more functional search application to use on Excel. The idea is to be able to perform a search of a user-specified set of key words in cells that contain target text that can have up to 600 words. The application would locate all cells with at least one match and displays the entire content of the cell in a textbox (in this case textbox7 in UserForm1) and would highlight the matching words in orange colored text for quick identification of the context of the key words within the target text.
For some reason I get an error message reading "Run-time error '438': Object doesn't support this property or method" and it highlights the line in my code reading: "With sh.TextBox".
Below I've included a copy of the code with the section where this error is occurring. From what I can see it looks like the error is the result of the way I've dimensioned variable "sh" (i.e as msforms.TextBox)
Ultimately what I need to achieve is something that will allow the use of "Characters" object which is a crucial part of this application because it locates the key words that have been found in the target text so that the font color can be changed to orange (and bold text).
I would be very grateful if someone can point out what the issue is and how I can go about resolving it. Thanks in advance.
Private Sub CommandButton2_Click()
'code below displays all email items found with at least one word match
Dim Position As Long
Dim EmlCharacterLength As Long
Dim KeyWordCharacterLength As Long
Dim sh As msforms.TextBox
Set sh = UserForm1.TextBox7
SlotCount2 = 0
If RA1Counter < NmbrItemsFound Then
Do While ResultsArray1(1, RA1Counter) = ResultsArray1(1, RA1Counter + 1)
RA1Counter = RA1Counter + 1
Loop
EmailCntr = EmailCntr + 1
TextBox2.Value = EmailCntr & " of " & NmbrEmails
TextBox3.Value = CorroArray(5, ResultsArray1(1, RA1Counter))
TextBox4.Value = CorroArray(2, ResultsArray1(1, RA1Counter))
TextBox5.Value = CorroArray(3, ResultsArray1(1, RA1Counter))
TextBox6.Value = CorroArray(0, ResultsArray1(1, RA1Counter))
TextBox7.Value = CorroArray(4, ResultsArray1(1, RA1Counter))
EmlCharacterLength = Len(CorroArray(4, ResultsArray1(1, RA1Counter)))
Do While SlotCount2 < NbrKeyWords + 1
Position = 1
KeyWordCharacterLength = Len(SplitKeyWords(SlotCount2))
Do While Position < EmlCharacterLength
Position = InStr(Position, CorroArray(4, ResultsArray1(1, RA1Counter)), SplitKeyWords(SlotCount2), 1)
With sh.TextBox
.Characters(Start:=Position, Length:=KeyWordCharacterLength).Font.Bold = True
.Characters(Start:=Position, Length:=KeyWordCharacterLength).Font.Color = RGB(255, 102, 0)
End With
Position = Position + KeyWordCharacterLength
Loop
SlotCount2 = SlotCount2 + 1
Loop
RA1Counter = RA1Counter + 1
Else
RA1Counter = 1
EmailCntr = 0
End If
End Sub

Excel - Using IF and OR

Here is my code as text:
Function NurZahl(ByVal Text As String) As Long
Dim i%, tmp
Dim Val As String
For i = 1 To Len(Text)
Val = Mid(Text, i, 1)
If(OR(IsNumeric(Val),Val=","),TRUE, FALSE) Then tmp = tmp & Mid(Text, i, 1)
Next i
NurZahl = tmp
End Function
Complete Beginner here:
What is my problem with the if?
Is there a possibility to show me the exact problem in excel?
The text is only highlighted with red color - if
i hover with the mouse-arrow above, there is no error message given.
This is my source of my knowledge for the structure of my if: Support Microsoft - Is this the wrong type of documentation for me?
Got the solution now with your help (thanks to everyone who replied) - I wanted to extract a number with decimal from a string:
Function CleanString(strIn As String) As String
Dim objRegex
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Global = True
.Pattern = "[^\d,]+"
CleanString = .Replace(strIn, vbNullString)
End With
End Function
The "If" line is written like an Excel formula. This is what is should look like in basic.
If IsNumeric(Val) Or Val = "," Then tmp = tmp & Mid(Text, i, 1)
The red text is a syntax error. If you go to the Debug menu and click Compile VBA Project, you'll get the error message.
The link that you included is for functions that are typed into a cell. You need a VBA reference. Here's a link to MS's reference, but a decent book would make your life a lot easier. Just search for "Excel VBA".
https://learn.microsoft.com/en-us/office/vba/api/overview/
You can try something like this:
Function NurZahl (ByVal MyText As String) As Long
' Set up the variables
Dim i as Integer
Dim tmp as String
Dim MyVal As String
' Start tmp with an empty string
tmp = ""
' Loop through each character of the input MyText
For i = 1 To Len(MyText)
' Read the character
MyVal = Mid(MyText, i, 1)
' Check whether the character is a number or a comma
' and take reasonable action
If IsNumeric(MyVal) or MyVal = "," then
tmp = tmp & Mid(MyText, i, 1)
End if
Next i
NurZahl = tmp
End Function
You'll have to change the code above to do what you want to do. The illustration above is to show how VBA code can be written.
In your VBA editor, when you see a red color on a line that means the editor has detected some issue with it.
If you were writing this function in Excel, you would typically use that function in a cell like this: =NurZahl(A1)

Translate formula quotation marks incl. replacements into VBA-readable formulae

Translate formula quotation marks incl. replacements into VBA-readable formulae
I was inspired to write this post by the recent question of
formula substitution using a constant.
At the same time, the frequent problem emerged that quotation marks
within a formula string should be replaced by double quotation marks in order
to make them readable in VBA.
Practical use case
A practical use case is to copy a table formula directly from a SO website
and "translate" it into a string-readable format.
But how is this supposed to be done with VBA means, since the direct input of
such an incomplete formula string in a procedure code without manually
added double quotation marks would immediately lead to an error?
Another feature would be to make replacements at certain points within
a formula template, for example with a constant or even with several
numerically identifiable markers.
I found a quick & dirty solution (without error handling) by analyzing a FormulaContainer procedure containing
exclusively outcommented formulae as these would allow any prior direct code input.
In order to distinguish them from the usual commentaries,
I decided with a heavy heart to use the Rem prefix (i.e. Remark) as an alternative, which we may still be familiar with from ancient Basic times.
My intention is not to show a perfect solution, but to stimulate further solutions
by demonstrating a possible way.
Question
Are there other work arounds allowing to copy tabular formulae with quotation marks directly and as possible replacement pattern into VBA procedures?
///////////////////////////////////
Main function QuickFormula()
References a FormulaContainer procedure containing exclusively formulae with Rem prefixes, such as e.g.
Sub FormulaContainer()
Rem =....
Rem =....
End Sub
This allows formula inputs with quotation marks similar to tabular cell inputs;
furthermore these inputs may contain string identifiers facilitating wanted replacements.
Option Explicit
'Site: https://stackoverflow.com/questions/70399681/how-many-quotes-to-put-around-a-formula-that-is-sending-an-empty-string
'Auth: https://stackoverflow.com/users/6460297/t-m
Function QuickFormula(ByVal no As Long, ParamArray repl() As Variant) As String
'Purp: - change indicated code line in FormulaContainer to code readable string and
' - replace enumerated identifiers with given value(s)
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'1) get REMark code line indicated by ordinal argument no
QuickFormula = getCodeLine("modFormula", "FormulaContainer", no)
'2a)replace "#" identifyer(s) with constant repl value
If Not IsArray(repl(0)) Then
QuickFormula = Replace(QuickFormula, "{1}", "#")
QuickFormula = Replace(QuickFormula, "#", repl(0))
If Len(QuickFormula) = 0 Then QuickFormula = "Error NA!"
Debug.Print no & " ~~> " & Chr(34) & QuickFormula & Chr(34)
Exit Function
End If
'2b)replace 1-based "{i}" identifiers by ParamArray values
Dim i As Long
For i = LBound(repl(0)) To UBound(repl(0))
QuickFormula = Replace(QuickFormula, "{" & i + 1 & "}", repl(0)(i))
Next
'3) optional display in immediate window
Debug.Print no & " ~~> " & Chr(34) & QuickFormula & Chr(34)
End Function
Help function getCodeLine()
Gets a given code line of the indicated procedure
Function getCodeLine(ByVal ModuleName As String, ByVal ProcedureName As String, Optional ByVal no As Long = 1) As String
'Purp: return a code line in given procedure containing "Rem "
'Note: assumes no line breaks; needs a library reference to
' "Microsoft Visual Basic for Applications Extensibility 5.3"
Const SEARCH As String = "Rem =", QUOT As String = """"
'1) set project
Dim VBProj As Object
Set VBProj = ThisWorkbook.VBProject
If VBProj.Protection = vbext_pp_locked Then Exit Function ' escape locked projects
'2) set component
Dim VBComp As Object
Set VBComp = VBProj.VBComponents(ModuleName)
Dim pk As vbext_ProcKind
'3) get no + 3 top code line(s)
With VBComp.CodeModule
'a)count procedure header lines
Dim HeaderCount As Long: HeaderCount = .ProcBodyLine(ProcedureName, pk) - .ProcStartLine(ProcedureName, pk)
'b) get procedure code
Dim codelines
'codelines = Split(.Lines(.ProcBodyLine(ProcedureName, pk), .ProcCountLines(ProcedureName, pk) - HeaderCount), vbNewLine)
codelines = Split(.Lines(.ProcBodyLine(ProcedureName, pk), no + 1), vbNewLine)
'c) filter code lines containing "Rem" entries
codelines = Filter(codelines, SEARCH, True)
End With
'4) return (existing) codeline no
If no - 1 > UBound(codelines) Then Exit Function ' check existance
getCodeLine = Replace(Replace(codelines(no - 1), QUOT, String(2, QUOT)), "Rem =", "=")
End Function
Example call
References all three formulae in the FormulaContainer (including an example of a non-existing number):
Sub EnterFormula()
With Sheet1.Range("X1") ' << change to any wanted target range
.Offset(1).Formula2 = QuickFormula(1, 6)
.Offset(2).Formula2 = QuickFormula(2, Array(10, 20, 30))
'two single argument inputs with same result
.Offset(3).Formula2 = QuickFormula(3, Array(17))
.Offset(4).Formula2 = QuickFormula(3, 17)
'not existing formula number in Rem code container
.Offset(5).Formula2 = QuickFormula(333, 17)
End With
End Sub
Example FormulaContainer
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Purp: formula container to be adjusted to code readable strings
'Note: Insert only Formulae starting with "Rem "-prefix!
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' # identifies constant replacement(s)
' {i} stands for enumerated replacements {1},{2}..{n}
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sub FormulaContainer()
Rem =IF($V#>0,IF($G#>$S#,($S#-$H#)*$K#+$Y#,($G#-$H#)*$K#+$Y#),"")
Rem =A{1}*B{3}+C{2}
Rem =A{1}+100
End Sub
Example output in immediate window
1 ~~> "=IF($V6>0,IF($G6>$S6,($S6-$H6)*$K6+$Y6,($G6-$H6)*$K6+$Y6),"""")"
2 ~~> "=A10*B30+C20"
3 ~~> "=A17+100"
3 ~~> "=A17+100"
333 ~~> "Error NA!"
Keep it simple stupid
Assuming either the currently selected cell formula or a textbox input, a simple Userform might act as a formula translator into a line of VBA code:
Basic Userform code
Needed: TextBox1, TextBox2, CommandButton1
Option Explicit
Private Sub CommandButton1_Click()
'Purp: Redouble inside quotation marks
Const Quot As String = """"
Dim assignTo As String
assignTo = "ws.Range(""" & Selection.Address(False, False) & """).Formula2 = "
Me.TextBox2.Text = assignTo & Quot & Replace(Me.TextBox1.Text, Quot, String(2, Quot)) & Quot
End Sub
Private Sub UserForm_Initialize()
'Purp: assume active formula as wanted input
Me.TextBox1 = Selection.Formula2
End Sub
Private Sub UserForm_Layout()
'Purp: example layout textboxes
'a) define textboxes
Dim textboxes() As String
textboxes = Split("Textbox1,Textbox2", ",")
'b) format
Dim i As Long
For i = 0 To UBound(textboxes)
With Me.Controls(textboxes(i))
.Font.Name = "Courier New"
.Font.Size = 12
.MultiLine = True
.EnterKeyBehavior = True
End With
Next i
End Sub
Possible extensions
Of course you might add an insertion routine (inserting e.g. {} brackets) as well as some replacement procedures like in my workaround above.
Just for fun, a basic insertion routine here:
Private Sub CommandButton2_Click()
'Purp: Insert brackets {}
With Me.TextBox1
.SetFocus
If InsertAtCursor("{}", Me.TextBox1) Then
.SelStart = .SelStart - 1
End If
End With
End Sub
Public Function InsertAtCursor(s As String, ctrl As MSForms.Control, Optional ErrMsg As String) As Boolean
'Purpose: Insert the characters at the cursor in the active control.
'Site: http://allenbrowne.com/func-InsertChar.html
'Return: True if characters were inserted.
'Arguments: s = the character(s) you want inserted at the cursor.
' ErrMsg = string to append any error messages to.
'Note: Control must have focus.
On Error GoTo Err_Handler
Dim prior As String 'Text before the cursor.
Dim after As String 'Text after the cursor.
Dim cnt As Long 'Number of characters
Dim iSelStart As Long 'Where cursor is.
Dim txt As String 'text with LineFeeds only
If s <> vbNullString Then
With ctrl ' --> UserForm Control
txt = Replace(.Text, vbCrLf, vbLf) ' LineFeeds only (MultiLine)
If .Enabled And Not .Locked Then
cnt = Len(txt) ' Zählung ohne vbCr's !
'SelStart can't cope with more than 32k characters.
If cnt <= 32767& - Len(s) Then
'Remember characters before cursor.
iSelStart = .SelStart
If iSelStart > 1 Then
prior = Left$(txt, iSelStart)
End If
'Remember characters after selection.
If iSelStart + .SelLength < cnt Then
after = Mid$(txt, iSelStart + .SelLength + 1) ' OP:2
End If
'Assign prior characters, new ones, and later ones.
.value = prior & s & after
'Put the cursor back where it as, after the new ones.
.SelStart = iSelStart + Len(s)
'Return True on success
InsertAtCursor = True
End If
End If
End With
End If
Exit_Handler:
Exit Function
Err_Handler:
Debug.Print Err.Number, Err.Description
Select Case Err.Number
Case 438&, 2135&, 2144& 'Object doesn't support this property. Property is read-only. Wrong data type.
ErrMsg = ErrMsg & "You cannot insert text here." & vbCrLf
Case 2474&, 2185& 'No active control. Control doesn't have focus.
ErrMsg = ErrMsg & "Cannot determine which control to insert the characters into." & vbCrLf
Case Else
ErrMsg = ErrMsg & "Error " & Err.Number & ": " & Err.Description & vbCrLf
End Select
Resume Exit_Handler
End Function

VBA Object with variable or block variable not set error even when is already set

I am currently trying to set conditions such that when a CSV file is not found in the folder, it will continue to find other CSV files. However I'm facing the "object with variable or block variable not set" error at the 2nd private sub readdatavcap2 even when I've already set Set o_file = fs2.OpenTextFile for both 1st and 2nd sub. I'm confused because for the 1st sub, the error does not occurs at o_file.Close after the else statement while for 2nd sub it occurs. Does anybody knows why?
Private Sub readdatavcap1(filename As String, i As Integer)
Application.ScreenUpdating = False
Dim sl As String
Dim first As Integer
Dim second As Integer
Dim j As Long
Dim fs2 As New Scripting.FileSystemObject
Dim o_file As Scripting.TextStream
j = 2 'variable not defined at fs2
If Dir(filename) <> "" Then
Set fs2 = CreateObject("Scripting.FileSystemObject") 'FileSystemObject also called as FSO, provides an easy object based model to access computer's file system.
'o_file contains filename(csv file link)
Set o_file = fs2.OpenTextFile(filename, 1, TristateFalse) '1=Open a file for reading only. You can't write to this file. TristateFalse means u get ascii file by default
'2=ForWriting, 8= Forappending
'o_file contains filename(text file data)
sl = o_file.readline 'Reads an entire line (up to, but not including, the newline character) from a TextStream file and returns the resulting string.
Do While Left(sl, 1) = "#" 'Left Function is used to extract N number of characters from a string from the left side.
sl = o_file.readline
Loop
Do While o_file.atendofstream <> True 'atendofstream = Read-only property that returns True if the file pointer is at the end of a TextStream file; False if it is not.
sl = o_file.readline
first = InStr(32, sl, ",", 1) - 15 'INSTR function returns the position of the first occurrence of a substring in a string.
second = InStr(first + 2, sl, ",", 1) 'syntax of InStr( [start], string, substring, [compare] )
'start sets string position for each search, string = string being search, substring= string expression searched ,
'eg:InStr(1, "Tech on the Net", "t") Result: 9 'Shows that search is case-sensitive
'compare= optional 1= textcompare
'searching for commas in the file in this case
If second = 0 Then
second = Len(sl) + 1 'len=length of file string
End If
If tddb_vramp = True Then
' write the Voltage Ramp to stress part
If i = 2 Then
ActiveWorkbook.Sheets("Ramp_current").Cells(j, 1) = Mid(sl, 2, first - 2)
End If
ActiveWorkbook.Sheets("Ramp_current").Cells(j, i) = Abs(Mid(sl, first + 2, second - 2 - first)) + 0.000000000000001
Else
'Write the normal current trace
ActiveWorkbook.Sheets("currentPTN_STI").Cells(j, 2 * i - 3) = Mid(sl, 15, first - 14)
' The MID function returns the specified number of characters in a text string, starting from a specified position (
'ie. starting from a specified character number).
'Use this function to extract a sub-string from any part of a text string. Syntax: MID(text_string, start_number, char_numbers).
ActiveWorkbook.Sheets("currentPTN_STI").Cells(j, 2 * i - 2) = Abs(Mid(sl, first + 2, second - 2 - first)) + 0.000000000000001
End If
j = j + 1
Loop
If tddb_vramp = False Then
myarray(i) = j - 1
End If
o_file.Close
Else
o_file.Close
End If
End Sub
Private Sub readdatavcap2(filename As String, i As Integer)
(rest of the code same as readdatavcap1)
.
.
.
o_file.Close
Else
o_file.Close <---error occurs here
End If
End Sub
I worked my way through your code but can't do more than confirm what GSerg already said in his first comment, i.e. you can't close a file that isn't open.
Option Explicit
Sub Main()
Dim SourceFolder As String
Dim Fn As String ' Filoe name
Dim i As Integer
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show = -1 Then ' if OK is pressed
SourceFolder = .SelectedItems(1)
End If
End With
If SourceFolder <> "" Then ' a folder was chosen
i = 2
Fn = Dir(SourceFolder & "\*.csv")
Do While Len(Fn) > 0
readdatavcap1 Fn, i
Fn = Dir
Loop
End If
End Sub
Private Sub readdatavcap1(filename As String, i As Integer)
' "filename" is a variable used by VBA
' your use of it may cause unexpected problems.
' to check, select the name and press F1.
Dim sl As String
Dim first As Integer
Dim second As Integer
Dim j As Long
Dim fs2 As New Scripting.FileSystemObject
Dim o_file As Scripting.TextStream
Dim tddb_vramp As Boolean
If Dir(filename) <> "" Then
Application.ScreenUpdating = False
j = 2 'variable not defined at fs2
' FileSystemObject also called as FSO, provides an easy object based model
' to access computer's file system.
Set fs2 = CreateObject("Scripting.FileSystemObject")
' o_file contains filename (csv file link)
' 1=Open a file for reading only. You can't write to this file.
' 2=ForWriting, 8= For appending
' TristateFalse means u get ascii file by default.
Set o_file = fs2.OpenTextFile(filename, 1, TristateFalse)
' o_file contains filename(text file data)
' Reads an entire line (up to, but not including, the newline character)
' from a TextStream file and returns the resulting string.
sl = o_file.readline
Do While Left(sl, 1) = "#"
' Left Function is used to extract N number of characters from a string from the left side.
sl = o_file.readline
Loop
' atendofstream = Read-only property that returns True if the file pointer
' is at the end of a TextStream file; False if it is not.
Do While o_file.atendofstream <> True
sl = o_file.readline
' INSTR function returns the position of the first occurrence of a substring in a string.
' syntax of InStr( [start], string, substring, [compare] )
' start sets string position for each search, string = string being search,
' substring= string expression searched ,
' eg:InStr(1, "Tech on the Net", "t") Result: 9
' Shows that search is case-sensitive
' compare= optional 1= textcompare
' searching for commas in the file in this case
first = InStr(32, sl, ",", 1) - 15 ' what if first is negative?
second = InStr(first + 2, sl, ",", 1)
If second = 0 Then
second = Len(sl) + 1 'len=length of file string
End If
' "ActiveWorkbook" seems not necessary unless you intend to have
' several workbooks, all having a sheet "Ramp_current" open at the
' same time, and none of them being ThisWorkbook.
' But if that's your intention "ActiveWorkbook" will lead to
' disaster sooner rather than later.
If tddb_vramp = True Then
' write the Voltage Ramp to stress part
If i = 2 Then
ActiveWorkbook.Sheets("Ramp_current").Cells(j, 1) = Mid(sl, 2, first - 2)
End If
ActiveWorkbook.Sheets("Ramp_current").Cells(j, i) = Abs(Mid(sl, first + 2, second - 2 - first)) + 0.000000000000001
Else
'Write the normal current trace
ActiveWorkbook.Sheets("currentPTN_STI").Cells(j, 2 * i - 3) = Mid(sl, 15, first - 14)
' The MID function returns the specified number of characters in a text string,
' starting from a specified position (ie. starting from a specified character number).
' Use this function to extract a sub-string from any part of a text string.
' Syntax: MID(text_string, start_number, char_numbers).
ActiveWorkbook.Sheets("currentPTN_STI").Cells(j, 2 * i - 2) = Abs(Mid(sl, first + 2, second - 2 - first)) + 0.000000000000001
End If
j = j + 1
Loop
If tddb_vramp = False Then
myarray(i) = j - 1
End If
o_file.Close
Application.ScreenUpdating = True
Else
' if Dir(filename) = "" The o_file doesn't exist
MsgBox filename & " wasn't found.", _
vbInformation, "Reading failure"
End If
End Sub
You should remove the Else condition from the above code. If you do that the code will do exactly nothing if the file isn't found. This fact would probably induce me to convert this procedure into a function that returns True if the file was found and False if it isn't. Perhaps that's helpful.
The point is that this procedure must be called by a Main proc which loops through all the files in a folder (for example) calling your proc with different file names. So, if your proc returns False the Main might issue a message saying that a file wasn't found. But even if you don't care for that, it's the Main that would select the next file after one has either been found and evaluated or not.

Search a string from text file & Return the Line Number using VBA

I have one text file that contains around 100K lines. Now I would like to search a string from the text file. If that string is present then I want to get the line number at which it's present. At the end I need all the occurrence of that string with line numbers from the text file.
* Ordinary Method Tried *
We can read the whole text file line by line. Keep a counter variable that increases after every read. If I found my string then I will return the Counter Variable. The limitation of this method is, I have to traverse through all the 100K lines one by one to search the string. This will decrease the performance.
* Quick Method (HELP REQUIRED)*
Is there any way that will directly take me to the line where my searchstring is present and if found I can return the line number where it's present.
* Example *
Consider below data is present in text file. (say only 5 lines are present)
Now I would like to search a string say "Pune". Now after search, it should return me Line number where string "pune" is present. Here in this case it's present in line 2. I should get "2" as an output. I would like to search all the occurrence of "pune" with their line numbers
I used a spin off of Me How's code example to go through a list of ~10,000 files searching for a string. Plus, since my html files have the potential to contain the string on several lines, and I wanted a staggered output, I changed it up a bit and added the cell insertion piece. I'm just learning, but this did exactly what I needed and I hope it can help others.
Public Sub ReadTxtFile()
Dim start As Date
start = Now
Dim oFSO As Object
Set oFSO = CreateObject("Scripting.FileSystemObject")
Dim oFS As Object
Dim filePath As String
Dim a, b, c, d, e As Integer
a = 2
b = 2
c = 3
d = 2
e = 1
Dim arr() As String
Do While Cells(d, e) <> vbNullString
filePath = Cells(d, e)
ReDim arr(5000) As String
Dim i As Long
i = 0
If oFSO.FileExists(filePath) Then
On Error GoTo Err
Set oFS = oFSO.OpenTextFile(filePath)
Do While Not oFS.AtEndOfStream
arr(i) = oFS.ReadLine
i = i + 1
Loop
oFS.Close
Else
MsgBox "The file path is invalid.", vbCritical, vbNullString
Exit Sub
End If
For i = LBound(arr) To UBound(arr)
If InStr(1, arr(i), "Clipboard", vbTextCompare) Then
Debug.Print i + 1, arr(i)
Cells(a + 1, b - 1).Select
Selection.Insert Shift:=xlDown
Cells(a, b).Value = i + 1
Cells(a, c).Value = arr(i)
a = a + 1
d = d + 1
End If
Next
a = a + 1
d = d + 1
Loop
Debug.Print DateDiff("s", start, Now)
Exit Sub
Err:
MsgBox "Error while reading the file.", vbCritical, vbNullString
oFS.Close
Exit Sub
End Sub
the following fragment could be repalaced like:
Dim arr() As String
Dim i As Long
i = 0
If oFSO.FileExists(filePath) Then
On Error GoTo Err
Set oFS = oFSO.OpenTextFile(filePath)
Do While Not oFS.AtEndOfStream
ReDim Preserve arr(0 To i)
arr(i) = oFS.ReadLine 'to save line's content to array
'If Len(oFSfile.ReadLine) = 0 Then Exit Do 'to get number of lines only
i = i + 1
Loop
oFS.Close
Else
MsgBox "The file path is invalid.", vbCritical, vbNullString
Exit Sub
End If
Here's another method that should work fairly quickly. It uses the shell to execute the FINDSTR command. If you find the cmd box flickers, do an internet search for how to disable it. There are two options provided: one will return the line number followed by a colon and the text of the line containing the keyword. The other will just return the line number.
Not sure what you want to do with the results, so I just have them in a message box.
Option Explicit
'Set reference to Windows Script Host Object Model
Sub FindStrings()
Const FindStr As String = "Pune"
Const FN As String = "C:\users\ron\desktop\LineNumTest.txt"
Dim WSH As WshShell
Dim StdOut As Object
Dim S As String
Set WSH = New WshShell
Set StdOut = WSH.Exec("cmd /c findstr /N " & FindStr & Space(1) & FN).StdOut
Do Until StdOut.AtEndOfStream
S = S & vbCrLf & StdOut.ReadLine
'If you want ONLY the line number, then
'S = S & vbCrLf & Split(StdOut.ReadLine, ":")(0)
Loop
S = Mid(S, 2)
MsgBox (S)
End Sub

Resources