Faster Way To Examine Text in AutoIt? - text-files

I'm attempting to use AutoIt to examine a text file and output select lines into a CSV. The problem I keep running into is that it takes forever. The current method examines a single line at a time. It can burn through 5-10 lines per second, but I'm looking for something much faster within the AutoIt framework.
Code:
#include <File.au3>
$xnConfirm = False
$xnConfirmMsg = 0
while $xnConfirm = False
$xnFile = FileOpenDialog("File to Examine...","%userprofile%","All (*.*)") ;InputBox("File???", "Which file do you want to review?","C:\")
If FileExists($xnFile) = True Then
$xnConfirm = True
Else
$xnConfirmMsg = msgbox(1,"File Not Found...",$xnFile & " does not exist." & #crlf & "Please select another file.")
EndIf
WEnd
$xnConfirm = False
$xnConfirmMsg = 0
while $xnConfirm = False
$xnTargetFile = FileOpenDialog("Location to Save to...",$xnFile & " - output.csv","All (*.*)");"%userprofile%\Documents\output.csv"
;FileSaveDialog("Location to Save to...","%userprofile%","All (*.*)",16,"output - " & $xnFile & " - output.csv") ;
Consolewrite("Outputting to " & $xnTargetFile & #crlf)
if fileexists($xnTargetFile) then
$xnConfirmMsg = msgbox(4,"Overwrite?","Are you sure you want to overwrite " & #crlf & $xnTargetFile)
if $xnConfirmMsg = 6 Then
$xnConfirm = True
filedelete($xnTargetFile)
EndIf
Else
$xnConfirm = True
EndIf
WEnd
progresson("Line count","Verifying the number of lines in " & $xnFile)
$xnFileLine = _FileCountLines($xnFile) ;InputBox("Number of lines","How many lines are in this document?",10000)
consolewrite("Loading "& $xnFile & " with " & $xnFileLine & " total lines." & #crlf)
progressoff()
local $hfl = FileOpen($xnFile,0)
FileWrite($xnTargetFile,"")
FileOpen($xnTargetFile, 1)
$i = 1
ProgressOn("Creating CSV","Extracting matching data.","",0,0,16)
$xnTargetLine = 1
FileWriteLine($xnTargetFile,"Timestamp,Message,Category,Priority,EventId,Severity,Title,Machine,App Domain,ProcessID,Process Name,Thread Name,Win32 ThreadId")
While $i < $xnFileLine
;$xnCurrentLine = FileReadLine($xnFile,$i) ;Old Settings
$xnCurrentLine = FileReadLine($hfl,$i)
;MsgBox(1,"",$xnCurrentLine)
Select
Case stringinstr($xnCurrentLine,"Timestamp:")
$xnTargetLine = stringmid($xnCurrentLine,12,stringlen($xnCurrentLine) - 12 + 1) & ","
Case stringinstr($xnCurrentLine,"Message:")
$xnTargetLine = $xnTargetLine & stringmid($xnCurrentLine,10,stringlen($xnCurrentLine) - 10 + 1) & ","
Case stringinstr($xnCurrentLine,"Category:")
$xnTargetLine = $xnTargetLine & stringmid($xnCurrentLine,11,stringlen($xnCurrentLine) - 11 + 1) & ","
Case stringinstr($xnCurrentLine,"Win32 ThreadId:")
$xnTargetLine = $xnTargetLine & stringmid($xnCurrentLine,16,stringlen($xnCurrentLine) - 16 + 1) & #crlf
FileWriteLine($xnTargetFile,$xnTargetLine)
case Else
consolewrite("Nothing on line " & $i & #crlf)
EndSelect
$i = $i + 1
ProgressSet(round($i/$xnFileLine * 100,1),$i & " of " & $xnFileLine & " lines examined." & #cr & "Thank you for your patience.")
WEnd
ProgressOff()
To address the question of what this is doing, I'm reading a log file similar to a trace log. I want the events to output to a CSV so I can examine trends. The format in the log file looks like this:
Timestamp: 9/26/2013 3:33:23 AM
Message: Log Event Received
Category: Transaction
Win32 ThreadId:2872
I know that's the code format, but I hope it's easier to read.

(I wanted to add a comment asking for a sampling of the data being read in, however I don't have enough points yet...)
Depending on the size of the input file I recommend reading the entire file into an array in one swoop using _FileReadToArray() and then looping through the array in memory (instead of keeping access to the file open during the entire process). In addition, I wouldn't write to the output file each time either - I'd write to a string and then save the string when completed.
Something like:
$outputFileData = ""
$inputFileData = _FileReadToArray($xnFile)
For $Counter = 1 to $inputFileData[0]
$tmpLine = $inputFileData[$Counter]
Select
Case stringinstr($tmpLine,"Timestamp:")
$outputFileData = stringmid($tmpLine,12,stringlen($tmpLine) - 12 + 1) & ","
Case stringinstr($tmpLine,"Message:")
$outputFileData &= stringmid($tmpLine,10,stringlen($tmpLine) - 10 + 1) & ","
Case stringinstr($xnCurrentLine,"Category:")
$outputFileData &= stringmid($tmpLine,11,stringlen($tmpLine) - 11 + 1) & ","
Case stringinstr($xnCurrentLine,"Win32 ThreadId:")
$outputFileData &= stringmid($tmpLine,16,stringlen($tmpLine) - 16 + 1) & #CRLF
case Else
ConsoleWrite("Nothing on line " & $i & #crlf)
EndSelect
Next
FileWriteLine($xnTargetFile, $outputFileData)
(Please note I didn't include any error checking nor did I check it for errors :)

Im not sure if it would be really faster but, you could use Regexp.
If you could tell me a little bit more what the rules are here:
Case stringinstr($xnCurrentLine,"Timestamp:")
$xnTargetLine = stringmid($xnCurrentLine,12,stringlen($xnCurrentLine) - 12 + 1) & ","
Case stringinstr($xnCurrentLine,"Message:")
$xnTargetLine = $xnTargetLine & stringmid($xnCurrentLine,10,stringlen($xnCurrentLine) - 10 + 1) & ","
Case stringinstr($xnCurrentLine,"Category:")
$xnTargetLine = $xnTargetLine & stringmid($xnCurrentLine,11,stringlen($xnCurrentLine) - 11 + 1) & ","
Case stringinstr($xnCurrentLine,"Win32 ThreadId:")
$xnTargetLine = $xnTargetLine & stringmid($xnCurrentLine,16,stringlen($xnCurrentLine) - 16 + 1) & #crlf
FileWriteLine($xnTargetFile,$xnTargetLine)
case Else
consolewrite("Nothing on line " & $i & #crlf)
and if you could give me 2 or 3 example lines i could try to make you a, Regexp function wich i think will be much faster.
Edit:
I Made an example Script.
If the Input File looks something like this:
Timestamp: 9/26/2013 3:33:23 AM
Message: Log Event Received
Category: Transaction
Win32 ThreadId:2872
Then This Script works just fine
#include <Array.au3>
Local $file = FileOpen("InputFile.txt", 0)
$sText = FileRead($file)
$aSnippets = StringRegExp($sText,"(?:Timestamp:|Message:|Category:|Win32 ThreadId:)(?: )?(.+)",3)
_ArrayDisplay($aSnippets)
The result is an array Containing the Following things:
[0] = 9/26/2013 3:33:23 AM
[1] = Log Event Received
[2] = Transaction
[3] = 2872
etc.
If you want to combine these 4 lines in one, try to use a for loop (if you want to, i can make you one)
For 100 Lines he Needs 0.490570878768441 Miliseconds to store every Value in one array.

There is an other possible idea.
You could copy the Input File, rename it, and then Delete every useles Data out of it.
That would be very easy with RegularExpressions and probably even faster.
If you show me a example of the Input File and how the Output file should look like i could try :)

Related

SAP GUI VBScript to cut & paste in chunks with data alteration

To get around a runtime error I need to read from an SAP table AGR_1251 in chunks using VBScript when I run a (SE16 | AGR_1251) query. I get this error TSV_TNEW_PAGE_ALLOC_FAILED - No more storage space available for extending an internal table.
As a work around, we manually copy 750 roles from the user by roles at a time, add a "*" to those that end with a certain character, then paste this back into the multiple select dialog to get the the AGR_1251 extract results in chunks.
I can't figure out how to do this in vbscript. How do I programmatically chunk this data? Ideally I would deduplicate it as well, but its not required.
The code has to run on both vbscript and in javascript, so I can't use excel or other windows tools like wscript. The best idea I have so far is to scroll through and copy just the roles to a file, read them back into an array and dedupe as I read them, then alter them, then loop back through the list to chuck out the results.
This is WAY above my nearly nonexistant vbscript skills. I can't be the only one who has had this problem. Can anyone point me to examples code that does this?
I'm open to suggestions on a better approach as well. I think my solution is fugly to say the least.
OK, this code is fugly with some unneeded variables, but it works.
Sub Save_AGR_1251s(Tcodes_array,Chunk_size)
Go_AGR_1251
writelog("Processing " & ubound(Tcodes_array) & " Tcodes in AGR_1251...")
k = 0
s = Chunk_size
max = ubound(Tcodes_array)
part = 0
roles_processed = 0
For i = 0 To max Step s
Go_AGR_1251
session.findById("wnd[0]/usr/txtMAX_SEL").text = ""
session.findById("wnd[0]/usr/txtMAX_SEL").setFocus
session.findById("wnd[0]/usr/txtMAX_SEL").caretPosition = 11
session.findById("wnd[0]/usr/btn%_I1_%_APP_%-VALU_PUSH").press
k = i + s
counter = 0
part = part + 1
If k > max Then k = max End If
For j = i To k-1
' writelog("Save_AGR_1251s Processing Tcode: " & Tcodes_array(j))
If (Tcodes_array(j) <> "STMS" or Tcodes_array(j) <> "SCC4") Then
'NOTE: The slow insert is used on XXXX Prod as a work around to odd UI behavior - change with caution - But SLOW!!
session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,7]").setFocus
session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,7]").text = Tcodes_array(j)
session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,7]").caretPosition = 1
'VKey 13 = Shift-F1 (insert new row)
session.findById("wnd[1]").sendVKey 13
If Debug_flag = True Then
writelog("i=" & i & " j=" & j & " k=" & k & " s=" & s &" max=" & max &" counter= " & counter)
writelog("part =" & part & " roles= " & roles & "roles_processed="& roles_processed & " Tcodes_array= " & Tcodes_array(j))
End If ' Debug_flag
counter = counter + 1
roles_processed = roles_processed + 1
End If ' Tcodes_array
Next 'for j to k
session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,1]").setFocus
session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,1]").caretPosition = 13
session.findById("wnd[1]/tbar[0]/btn[8]").press
session.findById("wnd[0]").sendVKey 8
session.findById("wnd[0]").sendVKey 45
session.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").select
session.findById("wnd[1]/usr/subSUBSCREEN_STEPLOOP:SAPLSPO5:0150/sub:SAPLSPO5:0150/radSPOPLI-SELFLAG[1,0]").setFocus
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[1]/usr/ctxtDY_PATH").text = dir
file_name = AGR_1251_filename & "_Part_" & part & c_dash & postfix & Datafile_ext
session.findById("wnd[1]/usr/ctxtDY_FILENAME").text = file_name
writelog("Saving file: " & dir & file_name)
session.findById("wnd[1]/usr/ctxtDY_FILE_ENCODING").text = File_encoding
session.findById("wnd[1]/usr/ctxtDY_PATH").setFocus
session.findById("wnd[1]/usr/ctxtDY_PATH").caretPosition = 16
session.findById("wnd[1]").sendVKey 11
Go_Home
Next ' For i
End Sub
Note that you can do this much faster on most systems by simply doing this
for i = 1 to 100
session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1," & 7 & "]").text = "Test " & i
next 'for i

Read a file's data within a specified range using VB script. Is it possible?

This is the middle of the code I'm trying to work with. Is there a way to make the file it's reading open and read from line 2 to line 97? Where I need the correction is starred (****). What I'm trying to do is get the data from lines 2 through 97 to compare to another file I'll have to open from the same lines. The beginning and ends of each file are different but the middle information should match thus I need these specific lines.
' Build Aliquot file name
strFile = aBarcodeExportDir & "A-" & yearStr & "-" & splitStr2(0) & ".csv"
'msgbox("open file: " & strFile)
If (objFS.FileExists(strFile)) Then
' Open A file
Set objFile = objFS.OpenTextFile(strFile)
' Build string with file name minus extension - used later to determine EOF
strFileNameNoExtension = "A-" & yearStr & "-" & splitStr2(0)
' Create dictionary to hold key/value pairs - key = position; value = barcode
Set dictA = CreateObject("Scripting.Dictionary")
' Begin processing A file
Do Until objFile.AtEndOfStream(*****)
' Read a line
strLine = objFile.ReadLine(*****)
' Split on semi-colons
splitStr = Split(strLine, ";")
' If splitStr array contains more than 1 element then continue
If(UBound(splitStr) > 0) Then
' If barcode field is equal to file name then EOF
If(splitStr(6) = strFileNameNoExtension) Then
' End of file - exit loop
Exit Do
Else
' Add to dictionary
' To calculate position
' A = element(2) = position in row (1-16)
compA = splitStr(2)
' B = element(4) = row
compB = splitStr(4)
' C = element(5.1) = number of max positions in row
splitElement5 = Split(splitStr(5), "/")
compC = splitElement5(0)
' position = C * (B - 1) + A
position = compC * (compB - 1) + compA
barcode = splitStr(6) & ";" & splitStr(0) & ";" & splitStr(1) & ";" & splitStr(2)
'msgbox(position & ":" & barcode)
' Add to dictionary
dictA.Add CStr(position), barcode
End If
End If
Loop
' Close A file
objFile.Close
To give the exact answer, we may have to look at your text files(I mean with all the split functions you are using). But, If you just want to compare lines 2-97 of two text files, you can get a hint from the following piece of code:
strPath1 = "C:\Users\gr.singh\Desktop\abc\file1.txt" 'Replace with your File1 Path
strPath2 = "C:\Users\gr.singh\Desktop\abc\file2.txt" 'Replace with your File2 Path
Set objFso = CreateObject("Scripting.FileSystemObject")
Set objFile1 = objFso.OpenTextFile(strPath1,1)
Set objFile2 = objFso.OpenTextFile(strPath2,1)
blnMatchFailed = False
Do Until objFile1.AtEndOfStream
If objFile1.Line=1 Then
objFile1.SkipLine() 'Skips the 1st line of both the files
objFile2.SkipLine()
ElseIf objFile1.Line>=2 And objFile1.Line<=97 Then
strFile1 = objFile1.ReadLine()
strFile2 = objFile2.ReadLine()
If StrComp(strFile1,strFile2,1)<>0 Then 'textual comparison. Change 1 to 0, if you want binary comparison of both lines
blnMatchFailed = True
intFailedLine = objFile1.Line
Exit Do 'As soon as match fails, exit the Do while Loop
Else
blnMatchFailed = False
End If
Else
Exit Do
End If
Loop
If blnMatchFailed Then
MsgBox "Comparison Failed at line "&intFailedLine
Else
MsgBox "Comparison Passed"
End If
objFile1.Close
objFile2.Close
Set objFile1 = Nothing
Set objFile2 = Nothing
Set objFso = Nothing

VBScript if typed response = Minute(now) Invalid procedure error

When you type the minute to be the same as the current minute (Ex. you type in 20 and its currently 1:20) I want it to end the script. Instead it gives me
Invalid procedure call or argument error.
Dim Ho, Mi, Se, RH, RM, RS
bOuterLoop = True
Do While bOuterLoop
reminder = InputBox(vbNewLine & "Enter a reminder for today," & " " &
WeekdayName(Weekday(Now())) & " " & MonthName (Month(Now)) & " " & (Day(Now)) & ", " & (Year(Now)) & "!", "Set a Reminder")
If IsEmpty(reminder) Then
WScript.Quit
End If
If reminder="" then
reminder="REMINDER FOR YOU"
end if
Ho = InputBox(vbNewLine & "At what hour would you like to be reminded?(24H)", "Time")
If IsEmpty(Ho) Then
WScript.Quit
End If
if Ho = "" then
WScript.Quit
End If
Mi = InputBox(vbNewLine & "At what minute in the hour do you want to be
reminded?", "Time")
If IsEmpty(Mi) Then
WScript.Quit
End If
if Mi = "" then
WScript.Quit
End If
RH = Hour(Now)
RM = Minute(Now)
RS = Second(Now)
if Mi = RM then
a=msgbox(reminder, 0, "")
wscript.quit
end if
Ho = Ho - RH
Se = RS
if RM > Mi then
Mi = Mi + 60
end if
Mi = Mi - RM
Do
WScript.Sleep (3600000 * Ho) + ((60000 * Mi) - (1000 * Se))
answer = MsgBox(reminder & " " & vbNewLine & vbNewLine & "Would you like to snooze the reminder? ", 4+64, "Reminder")
If answer = vbNo Then
WScript.Quit
bOuterLoop = False
Exit Do
End If
Loop
Loop
Please explain what I'm doing wrong.
I am not sure about the logic which you are using here but I think the 'If' condition comparing the values of variables 'Mi' and 'RM' is returning False.
Suppose the current time is 1:20.
In your code, the variable Mi stores the input taken from the user which is of type vbString. Suppose the user enters 20. So, your variable looks something like this:
Mi="20"
The variable RM stores Minute(now) which is of type vbInteger. So, it would look something like this:
RM=20
Now when you compare these two variables, they are not equal. Hence, the If condition returns False and your script does not end.
You can make the following change in your code:
If Cint(Mi) = RM then
a=msgbox(reminder, 0, "")
wscript.quit
End If

How do I find a repeating set of cells in Excel?

I Have a 2100 Rows and 6 Columns Table
Throughout the table there are only 12 Possible values, say A,B,C,D,E,F,G,H,I,J,K,L
The 12th value L is just a blank filler. It denotes blank cell.
Since there are only 11 possible values througout the table, patterns are observed.
First a Pattern Appears and it is later repeated somewhere in the table.
There can be any number of Patterns, but i have a specific format for a pattern which is to found and reported that way.
Solutions in EXCEL-VBA, PHP-MYSQL or C are welcome.
I have attached an example of what Iam looking for. Suggestions are most welcome to refine
the questions.
Information & Format : http://ge.tt/8QkQJet1/v/0 [ DOCX File 234 KB ]
Example in Excel Sheet : http://ge.tt/69htuNt1/v/0 [ XLSX File 16 KB ]
Please comment for more information or specific requirement.
Please try the code below, change the range to what you need it to be and the sheet number to the correct sheet number (I wouldn't put your full range in just yet because if you have 1000 pattern finds, you'll have to click OK on the message box 1000 times, just test with a partial range)
This will scan through the range, and find any pattern of two within a 10 row range, if you need it to find bigger patterns, youll need to add the same code again with an extra IF statement checking the next offset.
This will only find it if the same pattern exists and the same column structure is present, but its a start for you
Works fine on testing
Sub test10()
Dim rCell As Range
Dim rRng As Range
Set rRng = Sheets("Sheet1").Range("A1:I60") '-1 on column due to offset
'Scan through all cells in range and find pattern
For Each rCell In rRng.Cells
If rCell.Value = "" Then GoTo skip
For i = 1 To 10
If rCell.Value = rCell.Offset(i, 0).Value Then
If rCell.Offset(0, 1).Value = rCell.Offset(i, 1) Then
MsgBox "Match Found at: " & rCell.Address & ":" & rCell.Offset(0, 1).Address & " and " & rCell.Offset(i, 0).Address & ":" & rCell.Offset(i, 1).Address
End If
End If
Next i
skip:
Next rCell
End Sub
***UPDATE***
I have updated my code, the following now finds the pattern wherever it may appear in the next 10 rows:
Sub test10()
Dim rCell As Range
Dim rRng As Range
Dim r1 As Range
Dim r2 As Range
Set rRng = Sheets("Sheet1").Range("A1:I50") '-1 on column due to offset
i = 1 'row length
y = 0 'column length
'Scan through all cells in range and find pattern
For Each rCell In rRng.Cells
If rCell.Value = "" Then GoTo skip
i = 1
Do Until i = 10
y = 0
Do Until y = 10
xcell = rCell.Value & rCell.Offset(0, 1).Value
Set r1 = Range(rCell, rCell.Offset(0, 1))
r1.Select
ycell = rCell.Offset(i, y).Value & rCell.Offset(i, y + 1).Value
Set r2 = Range(rCell.Offset(i, y), rCell.Offset(i, y + 1))
If ycell = xcell Then
Union(r1, r2).Font.Bold = True
Union(r1, r2).Font.Italic = True
Union(r1, r2).Font.Color = &HFF&
MsgBox "Match Found at: " & rCell.Address & ":" & rCell.Offset(0, 1).Address & " and " & rCell.Offset(i, y).Address & ":" & rCell.Offset(i, y + 1).Address
Union(r1, r2).Font.Bold = False
Union(r1, r2).Font.Italic = False
Union(r1, r2).Font.Color = &H0&
End If
y = y + 1
Loop
i = i + 1
Loop
skip:
Next rCell
End Sub

MergeCol does not work while MergeRow does

I have a small MSFlexGrid with 1 fixed column, and 2 fixed rows.
As you can see MergeRow works in the top row.
I want the 2 top cells from the first column to merge as well, but the separation remains.
The code I am using is:
with grdPrm
.MergeCells = 1
.MergeRow(0) = True
.MergeCol(0) = True
.TextMatrix(1, 0) = .TextMatrix(0, 0)
End With 'grdPrm
I tried the values 0,1,2,3,4 for MergeCells as well as the constants flexMergeFree and flexMergeRestrictBoth.
Does anyone know why MergeCol does not work for me?
It appears that .TextMatrix(1, 0) = .TextMatrix(0, 0) does not make the contents exactly equal.
MergeCol does work when I replace that line with:
.TextMatrix(0, 0) = " "
.TextMatrix(1, 0) = " "
It probably has something to do that I originally filled TextMatrix(0,0) via the .FormatString property:
.FormatString = "^ " & "|> " & strFC(0) & " |> " & strFC(0) & " " & ......
Apparently .TextMatrix(1, 0) = .TextMatrix(0, 0) only assigns the contents, while MergeCol also checks for more than that (like explicit formatting)

Resources