Display search text in text file with VBA Excel - excel

I am new to VB and have a problem.
I have a text file named data.txt. It has 1 lines in it
IamanewstudentHeisanewstudentthestudentinthisclassisveryfunnythisuniversityhave300studentthestudentisveryfriendlywithnewcommer
I write a script which reads this text file and look for the string such as "stutent" and print all the "student" we can found in cell in excel (B1,C1,D1....). In this example we have 5 "student". It will display in cell B1,C1,D1,E1,F1 in sheet.
I tried till this point but it just give me only one "student" not five.
Sub SearchTextFile()
Const strFileName = "C:\data.txt"
Const strSearch = "student"
Dim strLine As String
Dim f As Integer
Dim lngLine As Long
Dim blnFound As Boolean
Dim lPosition As Long
f = FreeFile
Open strFileName For Input As #f
Do While Not EOF(f)
lngLine = lngLine + 1
Line Input #f, strLine
If InStr(1, strLine, strSearch, vbBinaryCompare) > 0 Then
blnFound = True
lPosition = InStr(1, strLine, strSearch, vbTextCompare)
MsgBox "Search string found" & strSearch, vbInformation
Exit Do
End If
Loop
Close #f
If Not blnFound Then
MsgBox "Search string not found", vbInformation
End If
End Sub

I would use RegEx to count the number of occurences in the line with the following function
Function noInStr(line As String, pattern As String) As Long
Dim regEx As Object, matches As Object
Set regEx = CreateObject("vbscript.regexp")
With regEx
.MultiLine = False
.Global = True
.IgnoreCase = True
.pattern = pattern
End With
Set matches = regEx.Execute(line)
noInStr = matches.count
End Function
You could use it in your code like that
Sub SearchTextFile()
Const strFileName = "C:\data.txt"
Const strSearch = "student"
Dim strLine As String
Dim f As Integer
Dim lngLine As Long
Dim blnFound As Boolean
Dim lPosition As Long
f = FreeFile
Open strFileName For Input As #f
Do While Not EOF(f)
lngLine = lngLine + 1
Line Input #f, strLine
Dim count As Long
count = noInStr(strLine, strSearch)
If count > 0 Then
blnFound = True
MsgBox "Search string found " & count & "- times: " & strSearch, vbInformation
Exit Do
End If
Loop
Close #f
If Not blnFound Then
MsgBox "Search string not found", vbInformation
End If
End Sub
If you also need the positions you could retrieve them with RegEx, too.
Update: This is how you could also retrieve the positions
Function colInStr(line As String, pattern As String) As Collection
Dim regEx As Object, matches As Object
Set regEx = CreateObject("vbscript.regexp")
With regEx
.MultiLine = False
.Global = True
.IgnoreCase = True
.pattern = pattern
End With
Set matches = regEx.Execute(line)
Dim col As New Collection
Dim i As Long
For i = 0 To matches.count - 1
col.Add matches(i).FirstIndex
Next i
Set colInStr = col
End Function
You also need to modify your code, below only the relevant part
Dim count As Long, col As Collection
Set col = colInStr(strLine, strSearch)
count = col.count
If count > 0 Then
blnFound = True
MsgBox "Search string found " & count & "- times: " & strSearch, vbInformation
Exit Do
End If
The positions are stored in the collection.

This will help find all the student strings and their right positions. I have commented my changes. I run the test using your file
Sub SearchTextFile()
Const strFileName = "C:\data.txt"
Const strSearch = "student"
Const strReplaceSearch = "tneduts"
Dim strLine As String
Dim f As Integer
Dim lngLine As Long
Dim blnFound As Boolean
Dim lPosition As Long
f = FreeFile
Open strFileName For Input As #f
Do While Not EOF(f)
lngLine = lngLine + 1
Line Input #f, strLine
'' For every line retreived, loop for all occurences of student
Do While (InStr(1, strLine, strSearch, vbBinaryCompare) > 0)
blnFound = True
lPosition = InStr(1, strLine, strSearch, vbTextCompare)
MsgBox "Search string found" & strSearch, vbInformation
'' remove the string student found and search for the next, we replace the word student with tneduts, that helps us keep the lPosition right
strLine = Replace(strLine, strSearch, strReplaceSearch, 1, 1)
Loop
Loop
Close #f
If Not blnFound Then
MsgBox "Search string not found", vbInformation
End If
End Sub

Related

How do you use MATCH in a loop?

I keep getting an error in the below code and its likely incorrect syntax.
I have tried replacing this line
IsInArray(pdfname, arNames(i)) = True
with this
Application.worksheetfunction.match(pdfname, arNames(i)) = True
but its not working.
Sub OpenPdf()
On Error GoTo OpenPdf_Error
Dim pdfname As String
Dim pdf
Const sPath = "S:\RA QUOTES 2019"
Dim FName As String
Dim arNames() As String
Dim myCount As Integer
Dim i As Integer
FName = Dir("S:\RA QUOTES 2019\*.pdf*")
Do Until FName = ""
myCount = myCount + 1
ReDim Preserve arNames(1 To myCount)
arNames(myCount) = FName
FName = Dir
Loop
pdfname = Application.InputBox("Enter the pdf you are looking for")
pdfname = "PLQ" & pdfname
For i = 1 To UBound(arNames)
If IsInArray(pdfname, arNames(i)) = True Then
ThisWorkbook.FollowHyperlink sPath & arNames(i)
End If
Next i
On Error GoTo 0
Exit Sub
OpenPdf_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure OpenPdf"
End Sub
This will work for an exact match using a dictionary (a collection data type which has the .Exists property which allows you to check if a key within the dictionary exists without looping through everytime).
Option Explicit
Sub OpenPdf()
Dim pdfname As String
Dim DictPDF As New Scripting.Dictionary 'Needs Microsoft Scripting Runtime
Const sPath = "S:\RA QUOTES 2019\"
Dim FName As String
Dim i As Integer
FName = Dir(sPath & "*.pdf*")
Do While FName <> vbNullString
'add the name into the dictionary
DictPDF.Add Left(LCase(pdfname), 7), 1 'Left will get the first 7 characters from the left to the name
FName = Dir
Loop
pdfname = Application.InputBox("Enter the pdf you are looking for")
pdfname = LCase("PLQ" & pdfname)
'Check if the name is in the dictionary I used LCase because dictionaries are case sensitive,
'so everything in low case to avoid problems.
If DictPDF.Exists(pdfname) Then
ThisWorkbook.FollowHyperlink sPath & DictPDF(pdfname)
Else
MsgBox pdfname & " was not found."
End If
End Sub
Sub OpenPdf()
On Error GoTo OpenPdf_Error
Dim pdfname As String
Dim pdf
Const sPath = "S:\RA QUOTES 2019\"
Dim FName As String
Dim arNames() As String
Dim myCount As Integer
Dim i As Integer
FName = Dir("S:\RA QUOTES 2019\*.pdf*")
Do Until FName = ""
myCount = myCount + 1
ReDim Preserve arNames(1 To myCount)
arNames(myCount) = FName
FName = Dir
Loop
pdfname = Application.InputBox("Enter the pdf you are looking for")
pdfname = "PLQ" & pdfname
For i = 1 To UBound(arNames)
If InStr(1, arNames(i), pdfname, vbTextCompare) Then
MsgBox (arNames(i))
ThisWorkbook.FollowHyperlink sPath & arNames(i)
End If
Next i
On Error GoTo 0
Exit Sub
OpenPdf_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure
OpenPdf"
End Sub

How to use most recent file according to filename pattern?

I have a folder with Excel files saved with the following format:
2018.01 final.xlsx
2018.02 final.xlsx
2018.03 final xlsx.
etc...
I would like to perform a VLOOKUP to find the most recent file according to the filename pattern. Today it would be 2018.08 final xlsx.
If the August file is not yet saved I would like to use the previous month, i.e. July (2018.07 final.xlsx).
The following code opens the latest file. I would like the newest file according to the pattern, without opening it.
fromPath = Sheets("Open latest file").Range("B5")
fromPath2 = Sheets("Open latest file").Range("B6")
If Dir(fromPath) = "" Then
Workbooks.Open (fromPath2)
Else
Workbooks.Open (fromPath)
End If
End Sub
Lucky for you I've already got a function I like to use that essentially does what you're looking for:
Function GetMostRecentExcelFile(ByVal myDirectory As String, ByVal filePattern As String) As String
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Dim myFolder As Object
Set myFolder = fso.getfolder(IIf(Right(myDirectory, 1) = "\", myDirectory, myDirectory & "\"))
Dim currentDate As Date
Dim fname As String
Dim currentFile As Object
For Each currentFile In myFolder.Files
If (currentDate = CDate(0) Or currentFile.DateCreated > currentDate) And currentFile.name Like filePattern _
And InStr(LCase$(currentFile.name), ".xlsx") > 0 And InStr(currentFile.name, "~$") = 0 Then
currentDate = currentFile.DateCreated
fname = currentFile.name
End If
Next currentFile
GetMostRecentExcelFile = fname
End Function
It will loop through the specified myDirectory looking for any files that match the filePattern that you give and will return the file with the most recently created file that matches said pattern.
Note: It does not pick the file based on filename, only based on the file's CreationDate!!
Here's how you'd most likely use it for your problem:
Sub Main()
Dim pattern As String
pattern = "*20##.## final*"
Dim path As String
path = sheets("Open latest file").Range("B5").Value2
Dim filename As String
filename = GetMostRecentExcelFile(path, pattern)
If Len(filename) = 0 Or Len(Dir(filename)) = 0 Then
path = sheets("Open latest file").Range("B6").Value2
filename = GetMostRecentExcelFile(path, pattern)
End If
If Len(filename) > 0 Then
Workbooks.Open (IIf(Right(path, 1) = "\", path, path & "\") & filename)
Else
MsgBox "No files found matching pattern"
End If
End Sub
I really like the answer #Marcucciboy2 has given you, but in case you can't trust that the last created file actually is the file you need, you could use (adapt offcourse) something like below:
Sub GetFile()
Dim YR As Long, MNTH As Long
Dim FPath As String, SearchFile As String
FPath = "U:\Test\"
For YR = Year(Now()) To 1 Step -1
For MNTH = 12 To 1 Step -1
If MNTH < 10 Then
SearchFile = FPath & YR & ".0" & MNTH & " final.xlsx"
Else
SearchFile = FPath & YR & "." & MNTH & " final.xlsx"
End If
If Dir(SearchFile) <> "" Then
Workbooks.Open (SearchFile)
Exit Sub
End If
Next MNTH
Next YR
End Sub
A welcome extra with this option is it wouldn't have to loop through all files saving some time.
You could try using regex to pattern match the files in a given folder. Do a little string manipulation to only retain the date part of the strings, then use sortedList to order the qualifying file names. Then select the last item from the ordered list as being your latest filename.
Option Explicit
Public Sub GetLastestFile()
Const PATH As String = "C:\Users\User\Desktop\Testing"
Dim fso As Object, oFolder As Object, oFile As Object, list As Object, tempString As String
Set list = CreateObject("System.Collections.SortedList")
Set fso = CreateObject("Scripting.FileSystemObject")
Set oFolder = fso.GetFolder(PATH)
For Each oFile In oFolder.Files
If IsFound(oFile.Name) Then
tempString = Replace$(Left$(oFile.Name, 7), ".", vbNullString)
With list
If Not .contains(tempString) Then
.Add tempString, vbNullString
End If
End With
End If
Next
Debug.Print list.Getkey(list.Count - 1)
End Sub
Public Function IsFound(ByVal inputString As String) As Boolean
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
With re
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = "\d{4}.\d{2}\sfinal.xlsx"
IsFound = .test(inputString)
End With
End Function
You can try the regex here.
Regex explanation:
\d{4}.\d{2}\sfinal.xlsx
\d{4} matches a digit (equal to [0-9])
{4} Quantifier — Matches exactly 4 times
. matches any character (except for line terminators)
\d{2} matches a digit (equal to [0-9])
{2} Quantifier — Matches exactly 2 times
\s matches any whitespace character (equal to [\r\n\t\f\v ])
final matches the characters final literally (case sensitive)
. matches any character (except for line terminators)
xlsx matches the characters xlsx literally (case sensitive)
Using a Class
Better still would be to implement a class for the regex that has a method IsFound. This would avoid the continual creation and destruction of the regex object. It would instead be created with the class instantiation and then just the method called as required.
If you create a class called RegexFileMatch then enter the following code:
Option Explicit
Private re As Object
Private Sub Class_Initialize()
Set re = CreateObject("VBScript.RegExp")
End Sub
Public Function IsFound(ByVal inputString As String) As Boolean
With re
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = "\d{4}.\d{2}\sfinal.xlsx"
IsFound = .test(inputString)
End With
End Function
Then change the calling code in the standard module to:
Option Explicit
Public Sub GetLastestFile()
Const PATH As String = "C:\Users\User\Desktop\Testing"
Dim fso As Object, oFolder As Object, oFile As Object, list As Object, tempString As String
Set list = CreateObject("System.Collections.SortedList")
Set fso = CreateObject("Scripting.FileSystemObject")
Set oFolder = fso.GetFolder(PATH)
Dim regex As New regexFileMatch
For Each oFile In oFolder.Files
If regex.IsFound(oFile.Name) Then
tempString = Replace$(Left$(oFile.Name, 7), ".", vbNullString)
With list
If Not .contains(tempString) Then
.Add tempString, vbNullString
End If
End With
End If
Next
Debug.Print list.Getkey(list.Count - 1)
End Sub
This becomes less expensive.
Sub FileFinder()
Dim strFile As String, strKey As String
Dim lngMax As Long, lngNumber As Long
Dim objDict As Object
Set objDictionary = CreateObject("scripting.dictionary")
intMax = 0
strFile = Dir("C:\Users\Documents\test\*.xlsx")
Do While Len(strFile) > 0
intNumber = f_NumberExtractor(strFile)
If lngMax < lngNumber Then
lngMax = lngNumber
End If
If objDictionary.exists(lngNumber) = False Then
objDictionary.Add lngNumber, strFile
End If
strFile = Dir
Loop
MsgBox objDictionary(lngMax)
End Sub
Public Function f_NumberExtractor(ByVal str As String) As Long
'Regular expression function to get rid of non-numeric signs
Dim objRegEx As Object
Dim lngResult As Long
Set objRegEx = CreateObject("VBScript.RegExp")
objRegEx.Pattern = "\D"
objRegEx.Global = True
lngResult = objRegEx.Replace(str, vbNullString) * 1
f_NumberExtractor = lngResult
End Function
A simplified version, credits to #QHarr..
My files are named as
IPG MEDIA BRANDS - UPDATE - 2020-10-12.txt
IPG MEDIA BRANDS - UPDATE - 2021-10-12.txt
So change te RegEx .Pattern = "\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])*" to fit your needs
Function GetLastestFile(path)
Set fso = CreateObject("Scripting.FileSystemObject")
Set oFolder = fso.GetFolder(path)
f = 0
For Each oFile In oFolder.Files
If CDate(FileDate(oFile.Name)) > f Then
last= oFile.Name
f = CDate(fechArchivo(oFile.Name))
End If
Next
GetLastestFile = last
End Function
Function FileDate(inputString)
Dim re As New RegExp
With re
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = "\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])*"
fechArchivo = .Execute(inputString)(0)
End With
End Function

Search list of strings in txt file via excel

I have many txt files in my folder. I have also have a list of their names in column 1, i need to search separate 1 string in each files which are listed in column 2. If such txt is found then it should say "Found" or else not found.
i was trying to modify below code based on my requirement but i unable to do it as its giving me the error for which i don't know the solution.
Sub SearchTextFile()
Dim FName, SName As String
Raise = 2
Do While Raise <> ""
FName = Cells(Raise, 1)
SName = Cells(Raise, 2)
Const strFileName = "Y:\New folder\" & FName & ".txt"
Const strSearch = SName
Dim strLine As String
Dim f As Integer
Dim lngLine As Long
Dim blnFound As Boolean
f = FreeFile
Open strFileName For Input As #f
Do While Not EOF(f)
lngLine = lngLine + 1
Line Input #f, strLine
If InStr(1, strLine, strSearch, vbBinaryCompare) > 0 Then
Cells(Raise, 3).Value = "Found"
blnFound = True
Exit Do
End If
Loop
Close #f
If Not blnFound Then
Cells(Raise, 3).Value = "Not Found"
End If
Raise = Raise + 1
Loop
End Sub
Try this modification
Sub Search_Text_Files()
Dim b As Boolean
Dim sName As String
Dim sSrch As String
Dim strFile As String
Dim sLine As String
Dim f As Integer
Dim r As Long
Dim l As Long
r = 2
Do While Cells(r, 1) <> ""
sName = Cells(r, 1)
sSrch = Cells(r, 2)
strFile = "Y:\New folder\" & sName & ".txt"
b = False
f = FreeFile
Open strFile For Input As #f
Do While Not EOF(f)
l = l + 1
Line Input #f, sLine
If InStr(1, sLine, sSrch, vbBinaryCompare) > 0 Then
Cells(r, 3).Value = "Found"
b = True: Exit Do
End If
Loop
Close #f
If Not b Then Cells(r, 3).Value = "Not Found"
r = r + 1
Loop
End Sub

Merge 2 Excel files with different columns, using a user form to select files and then column mapping

I need to merge two Excel files, but only certain columns from each. I need to use a userform to select the two files to merge and then also use column mapping to select which columns from each sheet need appear where in the new output sheet.
So far I have this.
Private Sub AddFilesButton_Click()
Dim arrFiles As Variant
On Error GoTo ErrMsg
'Let the user choose the files they want to merge
#If Mac Then
arrFiles = Select_File_Or_Files_Mac()
#Else
arrFiles = Application.GetOpenFilename("Excel Files (*.xls; *.xlsx), *.xls;*.xlsx", 1, "Choose Excel Files", "Select", True)
#End If
If IsNull(arrFiles) Or UBound(arrFiles) = -1 Then
MsgBox "Please choose at least one Excel file"
Else
For Each file In arrFiles
FilesListBox.AddItem file
Next file
MergeButton.Enabled = True
End If
ErrMsg:
If Err.Number <> 0 Then
MsgBox "There was an error. Please try again. [" & Err.Description & "]"
End If
End Sub
Private Sub CancelButton_Click()
Unload Me
End Sub
Private Sub MergeButton_Click()
Dim fileName As Variant
Dim wb As Workbook
Dim s As Sheet1
Dim thisSheet As Sheet1
Dim lastUsedRow As Range
Dim columnMap As Collection
Dim filePath As Variant
Dim dataRange As Range
Dim insertAtRowNum As Integer
Dim outColName As String
Dim colName As String
Dim fromRange As String
Dim fromRangeToCopy As Range
Dim toRange As String
On Error GoTo ErrMsg
Application.ScreenUpdating = False
Set thisSheet = ThisWorkbook.ActiveSheet
For i = 0 To FilesListBox.ListCount - 1
fileName = FilesListBox.List(i, 0)
'Get the map of columns for this file
Set columnMap = MapColumns(fileName)
'Open the spreadsheet in ReadOnly mode
Set wb = Application.Workbooks.Open(fileName, ReadOnly:=True)
For Each sourceSheet In wb.Sheets
'Get the used range (i.e. cells with data) from the opened spreadsheet
If firstRowHeaders And i > 0 Then 'Only include headers from the first spreadsheet
Dim mr As Integer
mr = wb.ActiveSheet.UsedRange.Rows.Count
Set dataRange = wb.ActiveSheet.UsedRange.Offset(1, 0).Resize(mr - 1)
Else
Set dataRange = wb.ActiveSheet.UsedRange
End If
For Each col In dataRange.Columns
'Get corresponding output column. Empty string means no mapping
colName = GetColName(col.Column)
outColName = GetOutputColumn(columnMap, colName)
If outColName <> "" Then
fromRange = colName & 1 & ":" & colName & dataRange.Rows.Count
Set fromRangeToCopy = dataRange.Range(fromRange)
fromRangeToCopy.Copy
toRange = outColName & insertAtRowNum & ":" & outColName & (insertAtRowNum + fromRangeToCopy.Rows.Count - 1)
thisSheet.Range(toRange).PasteSpecial
End If
Next col
insertAtRowNum = insertAtRowNum + dataRange.Rows.Count
Next sourceSheet
Application.CutCopyMode = False
Next i
ThisWorkbook.Save
Set wb = Nothing
#If Mac Then
'Do nothing. Closing workbooks fails on Mac for some reason
#Else
'Close the workbooks except this one
Dim file As String
For i = 0 To FilesListBox.ListCount - 1
file = FilesListBox.List(i, 0)
file = Right(file, Len(file) - InStrRev(file, Application.PathSeparator, , 1))
Workbooks(file).Close SaveChanges:=False
Next i
#End If
Application.ScreenUpdating = True
Unload Me
ErrMsg:
If Err.Number <> 0 Then
MsgBox "There was an error. Please try again. [" & Err.Description & "]"
End If
End Sub
Function MapColumns(fileName As Variant) As Object
Dim colMap As New Collection
Select Case fileName
Case "ExcelFile1.xlsx"
colMap.Add Key:="C", Item:="A"
colMap.Add Key:="D", Item:="B"
colMap.Add Key:="E", Item:="C"
colMap.Add Key:="I", Item:="D"
Case "ExcelFile2.xlsx"
colMap.Add Key:="B", Item:="F"
colMap.Add Key:="J", Item:="G"
colMap.Add Key:="H", Item:="H"
colMap.Add Key:="C", Item:="I"
End Select
Set MapColumns = colMap
End Function
Function GetOutputColumn(columnMap As Collection, col As String) As String
Dim outCol As String
outCol = ""
If columnMap.Count > 0 Then
outCol = columnMap.Item(col)
End If
GetOutputColumn = outCol
End Function
'From: http://www.mrexcel.com/forum/excel-questions/16444-getting-column-name-given-column-number.html
Function GetColName(ColumnNumber)
FuncRange = Cells(1, ColumnNumber).AddressLocal(False, False) 'Creates Range (defaults Row to 1) and retuns Range in xlA1 format
FuncColLength = Len(FuncRange) 'finds length of range reference
GetColName = Left(FuncRange, FuncColLength - 1) 'row always "1" therefore take 1 away from string length and you are left with column ref
End Function
'From: http://msdn.microsoft.com/en-us/library/office/hh710200%28v=office.14%29.aspx#odc_xl4_ta_ProgrammaticallySelectFileforMac_DifferencesWindowsandMac
Function Select_File_Or_Files_Mac() As Variant
Dim MyPath As String
Dim MyScript As String
Dim MyFiles As String
Dim MySplit As Variant
Dim N As Long
Dim Fname As String
Dim mybook As Workbook
On Error Resume Next
MyPath = MacScript("return (path to documents folder) as String")
'Or use MyPath = "Macintosh HD:Users:Ron:Desktop:TestFolder:"
' In the following statement, change true to false in the line "multiple
' selections allowed true" if you do not want to be able to select more
' than one file. Additionally, if you want to filter for multiple files, change
' {""com.microsoft.Excel.xls""} to
' {""com.microsoft.excel.xls"",""public.comma-separated-values-text""}
' if you want to filter on xls and csv files, for example.
MyScript = _
"set applescript's text item delimiters to "","" " & vbNewLine & _
"set theFiles to (choose file of type " & _
" {""com.microsoft.Excel.xls"",""org.openxmlformats.spreadsheetml.sheet""} " & _
"with prompt ""Please select a file or files"" default location alias """ & _
MyPath & """ multiple selections allowed true) as string" & vbNewLine & _
"set applescript's text item delimiters to """" " & vbNewLine & _
"return theFiles"
MyFiles = MacScript(MyScript)
On Error GoTo 0
MySplit = False 'Assume no files = cancel
If MyFiles <> "" Then
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
MySplit = Split(MyFiles, ",")
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End If
Select_File_Or_Files_Mac = MySplit
End Function
Function bIsBookOpen(ByRef szBookName As String) As Boolean
' Contributed by Rob Bovey
On Error Resume Next
bIsBookOpen = Not (Application.Workbooks(szBookName) Is Nothing)
End Function

How do I search for a string using Line Input and then print the next 5 lines in Excel cell

How do I search for a string, then when the string is found, write the entire line where the string is found, and then the next five lines into the same Cell in Excel using VBA?
Basically, I have a text file that I am importing into Excel using VBA. Based on a string, data from the file goes into cells under the appropriate column heading. The problem I am having is that some of my data is cut off at a line break. Due to the limitation of Line Input.
This condition does not happen for all values, just the ones with line breaks like this one:
How To Fix: To remove this functionality, set the following Registry key settings:
Hive: HKEY_LOCAL_MACHINE
Path: System\CurrentControlSet\Services...
Key: SomeKey
Type: DWORD
Value: SomeValue
Related Links: Some URL
I'm trying to get everything from How to Fix:... to Value:... to write to my Excel sheet, in the same Cell along with the data on the How to fix:... line.
I know that Input Line automatically stops at line breaks and moves on to the next line. Which, w/o the my loop attempts, is what the code below does.
If InStr(inputline, "How to Fix:") <> 0 Then
'Do While Not InStr(inputline, "Related Links:")
' Get rid of special characters in string
For i = 1 To Len(description)
sletter = Mid(description, i, i + 1)
iasc = Asc(sletter)
If Not (iasc <= 153 And iasc >= 32) Then
description = Left(description, i - 1) & " " & Right(description, Len(description) - i)
' End If
'Next
Do Until InStr(inputline, "Related Links:") = 1
description = Replace(description, "How to Fix:", "")
ws.Cells(rowndx4, 7).Value = Trim(description)
Loop
End If
I also tried using a FileSystemObject but it doesn't print anything to the Excel worksheet. The code is below:
Private Function ScanFile2$(FileToRead2 As String, rowndx4 As Long)
Dim wb As Workbook, ws As Worksheet, i As Long
Dim FNum3 As Integer, inputline As String, whatfile As Integer, testnum As String
Dim description As String
Dim finding As String
Set ws = ActiveWorkbook.Worksheets("Sheet1")
FNum3 = FreeFile()
Dim oFSO As FileSystemObject
Set oFSO = New FileSystemObject
Dim TS As TextStream
Const ForReading = 1
Set TS = oFSO.OpenTextFile(FNum3, ForReading)
Do While TS.AtEndOfStream <> True
inputline = TS.ReadAll
description = inputline
If InStr(inputline, "How To Fix:") <> 0 Then
description = Replace(inputline, "How To Fix:", "")
ws.Cells(rowndx4, 2).Value = inputline
End If
Exit Do
Loop
Close FNum3
Set ws = Nothing
Application.ScreenUpdating = True
ScanFile2 = rowndx4
End Function
This code
uses a RegExp to remove the linebreaks (replaced with a |) to flatten then string
then extracts each match with a second RegExp
change your filepath here c:\temo\test.txt
sample input and output at bottom
code
Sub GetText()
Dim objFSO As Object
Dim objTF As Object
Dim objRegex As Object
Dim objRegMC As Object
Dim objRegM As Object
Dim strIn As String
Dim strOut As String
Dim lngCnt As Long
Set objRegex = CreateObject("vbscript.regexp")
Set objFSO = CreateObject("scripting.filesystemobject")
Set objts = objFSO.OpenTextFile("c:\temp\test.txt")
strIn = objts.readall
With objRegex
.Pattern = "\r\n"
.Global = True
.ignorecase = True
strOut = .Replace(strIn, "|")
.Pattern = "(How to Fix.+?)Related"
Set objRegMC = .Execute(strOut)
For Each objRegM In objRegMC
lngCnt = lngCnt + 1
Cells(lngCnt, 7) = Replace(objRegM.submatches(0), "|", Chr(10))
Next
End With
End Sub
input
test
How To Fix: To remove this functionality, set the following Registry key settings:
Hive: HKEY_LOCAL_MACHINE
Path: System\CurrentControlSet\Services...
Key: SomeKey
Type: DWORD
Value: SomeValue
Related Links: Some URL
otherstuff
How To Fix: To remove this functionality, set the following Registry key settings:
Hive: HKEY_LOCAL_MACHINE
Path: System\CurrentControlSet\Services...
Key: SomeKey
Type: DWORD
Value: SomeValue2
Related Links: Some URL2
output
Here's the full code
Sub test()
' Open the text file
Workbooks.OpenText Filename:="C:\Excel\test.txt"
' Select the range to copy and copy
Range("A1", ActiveCell.SpecialCells(xlLastCell)).Select
Selection.Copy
' Assign the text to a variable
Set my_object = CreateObject("htmlfile")
my_var = my_object.ParentWindow.ClipboardData.GetData("text")
' MsgBox (my_var) ' just used for testing
Set my_object = Nothing
pos_1 = InStr(1, my_var, "How to fix:", vbTextCompare)
pos_2 = InStr(pos_1, my_var, "Related Links", vbTextCompare)
my_txt = Mid(my_var, pos_1, -1 + pos_2 - pos_1)
' Return to the original file and paste the data
Windows("stackoverflow.xls").Activate
Range("A1") = my_txt
' Empty the clipboard
Application.CutCopyMode = False
End Sub
This works for me...
first, assign the text in the text file to a variable (my_var in the example below)
pos_1 = InStr(1, my_var, "How to fix:", vbTextCompare)
pos_2 = InStr(pos_1, my_var, "Related Links", vbTextCompare)
my_txt = Mid(my_var, pos_1, -1 + pos_2 - pos_1)
Range("wherever you want to put it") = my_txt
You can also clean up my_txt using the "replace" function if you like.

Resources