Jump to content

Senseless Problem with filereadline


Recommended Posts

I might be missing something obvious here and if I am forgive me. However, I cannot figure out why this script isn't working the way I want it to work.

I have a text file I need to extract particular records from. While there is a ton of records in it the ones I need look like this:

[++b8cc8293-b1d1-11d6-ba8b-f575a629e04c++]
Name = 005
Type = Mark
CreateTime = 2002-08-18 02:09:42Z
Hidden = FALSE
Locked = FALSE
Desc = 
Color = 0x000000
LatLon = 58 24.92999 N 154 00.47400 W
BmpIdx = 0
ArrivalCircleRadius = 0.050 nm
NameOffset = -11,10
DescOffset = -15,20
ShowName = TRUE
ShowDescription = FALSE
RangeCircleColor = 0xff0000
RangeCircleDisplay Count = 0
RangeCirclePen Width = 1
BoundaryCircleOffLimits = None
RangeCircleRadius = 0.500 nm
RangeCircleBindToArrivalCircle = FALSE
MarkRenamed = FALSE
ExistsOutsideCollection = FALSE
PlanningLegSOG = 0.5 kts
NameDisplayMoved = FALSE
TDChain1 = 
TDChain2 =

Once I find Type = Mark the data I need is six lines down, the latlon field. Since this was meant to be quick and dirty I dashed off this:

$w=0
$WhattoOpen=FileOpen("C:\stpete\Export.Txt",0)
$WhattoWriteto=fileopen("C:\stpete\NobeltechMark.psv",1)
While 1
    $Checktheline=FileReadLine($WhattoOpen) ; read a line from the file
    $W = $W+1
    $IsitaMark=StringInStr($Checktheline,"Type = Mark") ;find out if it is a mark record
    If $IsitaMark <> 0 Then
        $Thisisthelatlon=FileReadLine($whattoopen,$w+6)
        filewrite($WhattoWriteto,$Thisisthelatlon & @CRLF)
        $isitamark=0
    endif
WEnd

When I look at the resulting text file this is what I see:

LatLon = 46 56.18280 N 124 26.64430 W

Type = Mark

Type = Mark

"Type = Mark" until the end of the file.

The first time Type = Mark is found I get what I want. However, every other time it does not appear to add 6 to the value of $W. I cannot figure out why this isn't working.

Edited by Mellon
Link to comment
Share on other sites

For starters you don't need to use the first FileOpen(). FileRead() will take care of that.

Based on the info you gave, I'm not sure if this is the results you are after or not but give it a try.

#include<array.au3>;; Used for displaying the array only.
$sStr = FileRead(C:\stpete\Export.Txt)
$aLatLonng = StringRegExp($sStr, "(?i)(?m:^)latl.+=\s*(\d.+)(?:\v|$)+", 3)
If NOT @Error <> 2 Then
    _ArrayDisplay($aLatLong);; Just for testing purposes
Else
    MsgBox(4096, "Error", "The expression did not match any data in the file.")
EndIf

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

I'm pretty sure this is what you're looking for :

#Include <File.au3>
$File = ''
For $A = 1 To _FileCountLines ($File)
    $Line = FileReadLine ($File, $A)
    If StringInStr ($Line, 'Type = Mark') Then FileWriteLine ('Export.txt', FileReadLine ($File, $A + 6))
Next

Hope this helps,

- John

Edited by z0mgItsJohn

Latest Projects :- New & Improved TCP Chat

Link to comment
Share on other sites

  • Moderators

I'm pretty sure this is what you're looking for :

#Include <File.au3>
$File = ''
For $A = 1 To _FileCountLines ($File)
    $Line = FileReadLine ($File, $A)
    If StringInStr ($Line, 'Type = Mark') Then FileWriteLine ('Export.txt', FileReadLine ($File, $A + 6))
Next

Hope this helps,

- John

Ouch, that's really inefficient :).

I'll try to explain why:

1. _FileCountLines: FileOpen, FileRead, FileClose, StringSplit, return array upper bound ( I assume this is how count lines works, haven't looked )

2. FileReadLine: FileOpen, read line, FileClose ( every single loop )

3. FileReadLine: FileOpen, read line + 6, FileClose ( every single loop, and past EOF for last 5 lines of the file )

4. FileWriteLine: FileOpen, write line, FileClose ( every single loop )

Now the above ( on semi large or many files ) would take an extremely long time for all that extra opening, closing, reading, writing...

Might try the same concept ( I'm not sure if it's what the OP wanted, I'm only showing your code change ), with less overhead:

Func _myFunction($s_filein, $s_filewriteto)
    
    ; 1 file open, read, close
    Local $s_fread = FileRead($s_filein)
    If Not $s_fread Then Return SetError(1, 0, 0)
    
    ; get lines of file ( this works if the file uses CRLF or at least LF
    ; for line separators
    Local $a_lines = StringSplit(StringStripCR($s_fread), @LF)
    
    Local $s_output = ""
    For $iline = 1 To $a_lines[0] - 6
        ; make sure the line is not null, then match string
        ; speed boost making sure it's not blank
        If $a_lines[$iline] And StringInStr($a_lines[$iline], "Type = Mark") Then
            $s_output &= $a_lines[$iline + 6] & @CRLF
        EndIf
    Next
    
    If Not $s_output Then Return SetError(2, 0, 0)
    
    ; 1 file open, write, close
    FileWrite($s_filewriteto, $s_output)
    Return 1
EndIf

This code is untested, I wrote it in this little post pane, more for concept than anything.

Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

Im curious now

I have a similar situaton but i have 6 users to check instead of one

Mark, Ted, Gary, Bob, Hannah and Matt

I suppose i could make 6 functions but there must be a better way than that?

Link to comment
Share on other sites

Hi Chimaera,

I suppose you could replace:

If $a_lines[$iline] And StringInStr($a_lines[$iline], "Type = Mark") Then

with a Regular expression, e.g. StringRegExp($a_lines[$iline],"(Type = Mark|Type = Peter)").

:)

Edited by Hannes123
Regards,Hannes[spoiler]If you can't convince them, confuse them![/spoiler]
Link to comment
Share on other sites

Like this you mean?

Func _myFunction($s_filein, $s_filewriteto)
    
    ; 1 file open, read, close
    Local $s_fread = FileRead($s_filein)
    If Not $s_fread Then Return SetError(1, 0, 0)
    
    ; get lines of file ( this works if the file uses CRLF or at least LF
    ; for line separators
    Local $a_lines = StringSplit(StringStripCR($s_fread), @LF)
    
    Local $s_output = ""
    For $iline = 1 To $a_lines[0] - 6
        ; make sure the line is not null, then match string
        ; speed boost making sure it's not blank
             StringRegExp($a_lines[$iline],"Mark", "Ted", "Gary", "Bob", "Hannah", "Mat") Then
            $s_output &= $a_lines[$iline + 6] & @CRLF
        EndIf
    Next
    
    If Not $s_output Then Return SetError(2, 0, 0)
    
    ; 1 file open, write, close
    FileWrite($s_filewriteto, $s_output)
    Return 1
EndIf
Link to comment
Share on other sites

  • Developers

All of which begs my question. Why does my script work correctly for the first record and then fail for all the rest?

You move the filepointer 6 records forward but do not add 6 to $w.

try below that has some debug lines in it so you can see what is happening:

$w=0
$WhattoOpen=FileOpen("Export.Txt",0)
$WhattoWriteto=fileopen("NobeltechMark.psv",1)
While 1
    $Checktheline=FileReadLine($WhattoOpen) ; read a line from the file
    If @error then ExitLoop
    $W += 1
    ConsoleWrite('@@ Debug : $W = ' & $W &  ' $Checktheline = ' & $Checktheline & @crlf) ;### Debug Console
    $IsitaMark=StringInStr($Checktheline,"Type = Mark") ;find out if it is a mark record
    If $IsitaMark <> 0 Then
        $Thisisthelatlon=FileReadLine($whattoopen,$w+6)
        ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $Thisisthelatlon = ' & $Thisisthelatlon & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
        filewrite($WhattoWriteto,$Thisisthelatlon & @CRLF)
        $W += 6
        $isitamark=0
    endif
WEnd

ps... the posted code would never end as you do not check for EOF...

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

  • Moderators

One, my apologies for not directly looking at your issue in my previous post.

Your text file looks like nothing more than an ini file to me.

This could solve your issue, however, I'm not a fan of it still opening and closing all the time, but it's a simple solution.

#include <array.au3> ; for _arraydisplay only
Global $gs_file = "test.txt"
Global $ga_lonslats = _myGetLatLon($gs_file, "Mark")
If IsArray($ga_lonslats) Then
    ConsoleWrite("Found " & $ga_lonslats[0] & " longitudes and latitudes." & @CRLF)
    _ArrayDisplay($ga_lonslats)
    ; Now you could enum through the array and write to the file if you wanted.
EndIf

Func _myGetLatLon($s_filein, $s_type)

    Local $a_secnames = IniReadSectionNames($s_filein)
    If @error Or Not IsArray($a_secnames) Then Return SetError(1, 0, 0)

    ; return array of longitudes and latitudes
    Local $a_ret[$a_secnames[0] + 1], $i_add = 0

    For $iname = 1 To $a_secnames[0]
        If IniRead($s_filein, $a_secnames[$iname], "Type", "") = $s_type Then
            $i_add += 1
            $a_ret[$i_add] = IniRead($s_filein, $a_secnames[$iname], "LatLon", "")
        EndIf
    Next

    If Not $i_add Then Return SetError(2, 0, 0)

    ReDim $a_ret[$i_add + 1]
    $a_ret[0] = $i_add

    Return $a_ret
EndFunc

Another method you might look at is regex ( quick and dirty ):

#include <array.au3> ; for _arraydisplay only
Global $gs_file = "test.txt"
Global $ga_lonslats = _myGetLatLon2($gs_file, "Mark")
If IsArray($ga_lonslats) Then
    ConsoleWrite("Found " & $ga_lonslats[0] & " longitudes and latitudes." & @CRLF)
    _ArrayDisplay($ga_lonslats)
    ; Now you could enum through the array and write to the file if you wanted.
EndIf

Func _myGetLatLon2($s_filein, $s_type)

    Local $s_fread = FileRead($s_filein)
    If $s_fread = "" Then Return SetError(1, 0, 0)

    Local $s_pattern = "(?is)(?:\A|\v)Type\s*=\s*\Q" & $s_type & "\E"
    $s_pattern &= "\s*\v.+?\vLatLon\s*=\s*(.+?)\s*(?:\v|\z)"

    Local $a_sre = StringRegExp($s_fread, $s_pattern, 3)
    If @error Then Return SetError(2, 0, 0)

    ; comment out below if you want a zero base array and
    ;  just return $a_sre

    ; convert to 1 base array where [0] has total number of indexes
    Local $i_ub = UBound($a_sre)
    Local $a_ret[$i_ub + 1] = [$i_ub]

    For $i = 0 To $i_ub - 1
        $a_ret[$i + 1] = $a_sre[$i]
    Next

    Return $a_ret
EndFunc
Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...