Jump to content
Sign in to follow this  
kiffab

String - find only the first instance

Recommended Posts

kiffab

Hi there

I am looking to read a file backwards into an array then search for a particular string. When the string is found, I want to output it (at least when testing). I only want to output the first occurrence.

I've searched around this forum, combining code from different posts but it outputs every occurence of the string. How would I change this to do as stated above?

Thanks! :)

#include <file.au3>

$File_Name = "mylog.log"
$Find = "hello"

Dim $Records
If ReadFileBackwards("mylog.log", $Records) Then
For $x = $Records[0] To 1 Step - 1
if StringInStr($Records[$x], $Find) Then Msgbox(0,'Record:' & $x, $Records[$x])
Next
Else

EndIf
Exit

Func ReadFileBackwards($SFilepath, ByRef $AArray)
Local $HFile
 $HFile = FileOpen($SFilepath, 0)
 If $HFile = -1 Then
 SetError(1)
 Return 0
 EndIf
 $AArray = StringSplit( StringStripCR( FileRead($HFile, _
 FileGetSize($SFilepath))), @LF)
 FileClose($HFile)
 Return 1
EndFunc

Share this post


Link to post
Share on other sites
kiffab

Hmm... is ubound the way to go here?

for $x = $Records[0] to Ubound ($Records) -1

Share this post


Link to post
Share on other sites
Jos

Something like this?

#include <file.au3>
$File_Name = "mylog.log"
$Find = "hello"
Global $Records
_FileReadToArray("mylog.log",$Records)
For $x = $Records[0] To 1 Step -1
    If StringInStr($Records[$x], $Find) Then
        MsgBox(0, 'Record:' & $x, $Records[$x])
        ExitLoop
    EndIf
Next

Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
kiffab

That works Jos. Thank you! Basically what I'm trying to do is find a string, then find another string and determine which one is the latest entry in the log file. From that I will be able to set the status of a variable :)

Edited by kiffab

Share this post


Link to post
Share on other sites
Jos

That works Jos. Thank you! Basically what I'm trying to do is find a string, then find another string and determine which one is the latest entry in the log file. From that I will be able to set the status of a variable :)

Should be easy ... add the tests after the Next for what you want to test for:

#include <file.au3>
$File_Name = "mylog.log"
$Find1 = "hello"
$Find2 = "goodbye"
Global $Records, $Found1=False, $Found2=False 
_FileReadToArray("mylog.log",$Records)
For $x = $Records[0] To 1 Step -1
    If StringInStr($Records[$x], $Find1) Then $Found1 = $x
    If StringInStr($Records[$x], $Find2) Then $Found2 = $x
    If $Found1 and $Found2 then ExitLoop
Next

Visit the SciTE4AutoIt3 Download page for the latest versions  - Beta files                                How to post scriptsource        Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites
kiffab

Thanks Jos. I had done this using variables x and y in 2 separate for loops but this seems more efficient :)

Appreciate your help!

Should be easy ... add the tests after the Next for what you want to test for:

#include <file.au3>
$File_Name = "mylog.log"
$Find1 = "hello"
$Find2 = "goodbye"
Global $Records, $Found1=False, $Found2=False 
_FileReadToArray("mylog.log",$Records)
For $x = $Records[0] To 1 Step -1
    If StringInStr($Records[$x], $Find1) Then $Found1 = $x
    If StringInStr($Records[$x], $Find2) Then $Found2 = $x
    If $Found1 and $Found2 then ExitLoop
Next

Share this post


Link to post
Share on other sites
kiffab

Jos,

I have created a GUI and included the function. If I call it outside the while loop, it works. That only lets me read the log once. I want to read it repeatedly, say every 1 minute. I tried using sleep command and placing it in the while loop. Also tried activating it by pressing the start button but no joy. Where am I going wrong?

Thanks.

#include <file.au3>
#include <GUIConstantsEx.au3>

Global $logFile = @scriptdir & "/mylog.log"
$find1= "server1on"
$find2 = "server1off"

$status = ""

Func Test()
Global $Records, $Found1=False, $Found2=False
_FileReadToArray($logFile,$Records)
For $x = $Records[0] To 1 Step -1
    If StringInStr($Records[$x], $find1) Then $Found1 = $x
    If StringInStr($Records[$x], $find2) Then $Found2 = $x
    If $Found1 and $Found2 then ExitLoop
Next
If $Found1 > $Found2 Then $status = "ON"
EndFunc

$GUI = GUICreate("App", 400, 400)
GUICtrlCreatePic('bg.bmp', 0, 0, 400, 400)
GuiCtrlSetState(-1,$GUI_DISABLE)
GUISetFont(9, 1, 3, "verdana")
GUISetState()

GUICtrlCreateLabel("server1", 10, 10, 80, 30)
GuiCtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

GUICtrlCreateLabel($status, 100, 10, 80, 30)
GuiCtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

$start = GUICtrlCreateButton("Start",10, 160, 80, 30)

While 1

    $msg = GUIGetMsg()
    Switch $Msg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $start
            Test()
    EndSwitch

WEnd

;GUIDelete() ; not sure if this is needed

Exit

Share this post


Link to post
Share on other sites
jchd

_ArraySearch with Partial = 1 and Forward = 0 should be your one-liner for this.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites
kiffab

In the function or within the while loop?

Thx

Share this post


Link to post
Share on other sites
kiffab

Instead of the loop ;)

Sorry if I'm being stupid here... how would this work? Would I not need a for loop or something so the log file would be read every x seconds/minutes?

:)

Appreciate the help you guys have given me ;)

Share this post


Link to post
Share on other sites
Malkey

Sorry if I'm being stupid here... how would this work? Would I not need a for loop or something so the log file would be read every x seconds/minutes?

....

Change AdlibRegister("MyAdlib", 6000) to AdlibRegister("MyAdlib", 60000) for every 60 seconds.

A test "mylog.log" file used.

Line 1
Hello 2
Line 3
Hello 4
Line 5
Hello 6
Line 7

An example.

#include <file.au3>
#include <Array.au3>

HotKeySet("{ESC}", "Terminate")

AdlibRegister("MyAdlib", 6000) ; 6000 millsec = 6 seconds

Global $sFile_Name = @ScriptDir & "\mylog.log"
Global $sFind1 = "hello"
Global $sFind2 = "line"

;Initial MsgBox
MsgBox(0, "Press ESC to Exit", 'Last "' & $sFind1 & '" is in the line "' & _FindInLog($sFile_Name, $sFind1) & '".' & @LF & _
        'Last "' & $sFind2 & '" is in the line "' & _FindInLogA($sFile_Name, $sFind2) & '".', 4)

While 1
    Sleep(50)
WEnd


Func MyAdlib()
    MsgBox(0, "Press ESC to Exit", 'Last "' & $sFind1 & '" is in the line "' & _FindInLog($sFile_Name, $sFind1) & '".' & @LF & _
            'Last "' & $sFind2 & '" is in the line "' & _FindInLogA($sFile_Name, $sFind2) & '".', 4)
EndFunc   ;==>MyAdlib

; _FindInLog() returns the line that $Find1 is found in.
Func _FindInLog($File_Name, $Find)
    Local $Records
    _FileReadToArray($File_Name, $Records)
    #cs
        For $x = $Records[0] To 1 Step -1
        If StringInStr($Records[$x], $Find1) Then $Found1 = $x
        If StringInStr($Records[$x], $Find2) Then $Found2 = $x
        If $Found1 And $Found2 Then ExitLoop
        Next
    #ce
    Local $iIndex = _ArraySearch($Records, $Find, 0, 0, 0, 1, 0)
    Return $Records[$iIndex]
EndFunc   ;==>_FindInLogA

;or

; _FindInLogA() returns the line that $Find1 is found in.
Func _FindInLogA($File_Name, $Find)
    Return StringRegExpReplace(FileRead($File_Name), "(?mis)^.*([^\v]*" & $Find & "[^\v]*).*", "\1")
EndFunc   ;==>_FindInLog

Func Terminate()
    AdlibUnRegister("MyAdlib")
    Exit 0
EndFunc   ;==>Terminate

Edit: Changed RegExp from "(?is)^.*\v([^\v]*" & $Find & "[^\v]*).*" to match first line.

Edit2: Changed RegExp from "(?is)^.*\v|\A([^\v]*" & $Find & "[^\v]*).*" to match first line.

Edited by Malkey

Share this post


Link to post
Share on other sites
kiffab

Thanks for your input Malkey. I was working on this last night and almost have it working as I want. My only problem is the X button in the top right corner won't work.

I tried adding the lines:

Case $msg = $GUI_EVENT_CLOSE

ExitLoop

but I've had to comment these out as the application closes immediately when they are present. My Exit button works fine but I'd like the X to work too!

What am I missing? AdlibUnregister?

Thanks again!

#include <Array.au3>
#include <file.au3>
#include <GUIConstantsEx.au3>

$find1 = "on"
$find2 = "off"

Global $logFile = @scriptdir & "/mylog.log"
Global $Records

$GUI = GUICreate("App", 300, 400)
;GUICtrlCreatePic('bg.bmp', 0, 0, 300, 400) ;set the background image
GuiCtrlSetState(-1,$GUI_DISABLE) ;disable gui
GUISetFont(12, 600, 1, "verdana")

GUICtrlCreateLabel("Server 1", 10, 30, 100, 40)
GuiCtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

$server1status = GUICtrlCreateLabel("Default", 10, 100, 80, 30)
GuiCtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

$Start = GUICtrlCreateButton("Start", 20, 350, 80, 40)
$Exit = GUICtrlCreateButton("Exit", 130, 350, 80, 40)

Func Server1()

    _FileReadToArray($logFile,$Records)
    $iIndex1 = _ArraySearch($Records, $find1, 0, 0, 0, 1, 0)
    $iIndex2 = _ArraySearch($Records, $find2, 0, 0, 0, 1, 0)

    If $iIndex1 > $iIndex2 Then
        GUICtrlSetData($server1status, "On")
        Else
        GUICtrlSetData($server1status, "Off")
    EndIf

EndFunc

GUISetState()

while 1

    $msg = GUIGetMsg()

    Switch $msg
        case $Exit
            Exit
        case $start
            AdlibRegister("server1",10000)
        ;Case $msg = $GUI_EVENT_CLOSE
        ;   ExitLoop
    EndSwitch

WEnd

GUIDelete()

Exit

Share this post


Link to post
Share on other sites
Malkey

....

I tried adding the lines:

Case $msg = $GUI_EVENT_CLOSE

ExitLoop

....

That Case statement is used in in a Select ... EndSelect routine.

Use

Case  $GUI_EVENT_CLOSE
    ExitLoop

For a Switch....EndSwitch routine.

Share this post


Link to post
Share on other sites
kiffab

That Case statement is used in in a Select ... EndSelect routine.

Use

Case  $GUI_EVENT_CLOSE
    ExitLoop

For a Switch....EndSwitch routine.

Fantastic. Thank you. I knew it was something silly :)

Basic logic is pretty much there. The only other thing I've noticed is that if you click "Start", it waits 10 seconds, then another 10 seconds before updating the status (20 secondS).

I've cut this down to 10 seconds by calling the function before the AdlibRegister:

case $start
    server1()
    AdlibRegister("server1",10000)

Is it possible to update the status as soon as start is pressed? i.e. press start - change status to what it should be then 10 seconds later read file again and repeat?

Cheers

Share this post


Link to post
Share on other sites
Malkey

I have been playing with your script. It appears to be working fine.

#include <Array.au3>
#include <file.au3>
#include <GUIConstantsEx.au3>

Global $find1 = "on"
Global $find2 = "off"

Global $logFile = @ScriptDir & "/mylog.log"
Global $Records
Local $msg

Local $GUI = GUICreate("App", 300, 400)
GUISetFont(12, 600, 1, "verdana")

;GUICtrlCreatePic('bg.bmp', 0, 0, 300, 400) ;set the background image
;GUICtrlSetState(-1, $GUI_DISABLE) ; disable Pic control.

GUICtrlCreateLabel("Server 1", 10, 30, 100, 40)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

Local $server1status = GUICtrlCreateLabel("Default", 10, 100, 80, 30)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

Local $Start = GUICtrlCreateButton("Start Server Check", 20, 350, 130, 20)
GUICtrlSetFont(-1, 8, 600)

Local $Exit = GUICtrlCreateButton("Stop Server Check", 155, 350, 130, 20)
GUICtrlSetFont(-1, 8, 600)

GUISetState()

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case -3 ; $GUI_EVENT_CLOSE = -3, as declared in #include <GUIConstantsEx.au3>.
            ExitLoop
        Case $Start
            Server1()
            AdlibRegister("server1", 10000)
        Case $Exit
            GUICtrlSetData($server1status, "Default")
            AdlibUnRegister("server1")
    EndSwitch
WEnd

AdlibUnRegister("server1")


Func Server1()
    _FileReadToArray($logFile, $Records)
    Local $iIndex1 = _ArraySearch($Records, $find1, 0, 0, 0, 1, 0)
    Local $iIndex2 = _ArraySearch($Records, $find2, 0, 0, 0, 1, 0)
    ConsoleWrite("if " & $iIndex1 & " > " & $iIndex2 & ' then "on"' & @LF) ; Testing purposes only.
    If $iIndex1 > $iIndex2 Then
        GUICtrlSetData($server1status, "On")
    Else
        GUICtrlSetData($server1status, "Off")
    EndIf
EndFunc   ;==>Server1

Share this post


Link to post
Share on other sites
kiffab

I have been playing with your script. It appears to be working fine.

Thanks Malkey. I've changed this slightly to use images which should update depending on the status. I've noticed they flicker when you click start (but remain at default setting) then after 10 seconds they will change to the correct image.

Not sure why the image doesn't change as soon as start is clicked.

Cheers.

Share this post


Link to post
Share on other sites
kiffab

Thanks Malkey. I've changed this slightly to use images which should update depending on the status. I've noticed they flicker when you click start (but remain at default setting) then after 10 seconds they will change to the correct image.

Not sure why the image doesn't change as soon as start is clicked.

Cheers.

Calling the function twice when start is clicked seems to fix this. Not sure if that's bad practice or not, but it works. :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×