Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

TF: Text file & Variables/String Library v3.4 [lib]


  • Please log in to reply
244 replies to this topic
SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
v2.4a fix, 10 August 2009:

- The fix for TF_SplitFileBy* functions of 2.3b wasn't complete, now it should work correctly (it didn't write the last file)

Note to self: test those 'fixes' :oops:

Forg1ven
  • Guests
  • Last active:
  • Joined: --
This is great! Thank you so much!

I have a suggestion, could you make a function to remove dates? Such as anything matching the format **/**/**** or **/**/**.

Or if there is a way to do this please tell me I've searched and tried to figure it out on my own.

SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
This should do the trick, readup on RegEx in the AHK Help. \d is digit.
TF_RegExReplace("file.txt", "\d\d/\d\d/\d{2,4}", "")


ruespe-nli
  • Guests
  • Last active:
  • Joined: --
Really a great job, HugoV. Congratulations and thanks for sharing. :D

Wouldn't it be nice to have the posibillity, not only to manipulate files but also variables? So one can read a file into a variable and do several manipulations without always reading and writing.

Just an idea.

Rog

SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
That is on my TODO list :wink: I suggested it to Heresy when he started. I have various ideas on how to do it just need to experiment with it to see
what works and what would be effective - but first a few more functions
just because that is so much fun

aaffe
  • Members
  • 1045 posts
  • Last active: Jan 16 2014 01:32 PM
  • Joined: 17 May 2007
Sorry, wrong post.... <- deleted

SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
I think the next release will be a rewrite of the library as I'm thinking of making the TF lib a wrapper for a string manipulation library.

That way the same functions can be used for strings and text files
avoiding the need to maintain two separate almost identical libraries OR
by adding another prefix or parameter to each function to make it work
with strings (variables) in the TF lib

engunneer
  • Moderators
  • 9162 posts
  • Last active: Sep 12 2014 10:36 PM
  • Joined: 30 Aug 2005
or just make it check the string to see if it happens to be a file?

A hack, but it's what I would do.

SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
I have tested that a while ago and thought is was a fugly solution but I may revisit it. But everything would be better than yet another parameter I suppose.

SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
OK, so I'm considering three options to "upgrade" TF.ahk to also process strings (vars) and not just textfiles.

a) create a string library with similar functions and possibly make TF.ahk a wrapper for the string lib
B) Currently ! is used to indicate overwrite the source file or not, I could simply introduce ? (or other char) to indicate something is a var but that would preclude vars starting with a ?
c) the solution below where I added a function that tries to determine if something is a file or a variable and act accordingly. Before upgrading the entire library I would like to have some feedback and suggestions, you can try the code below indepently of the lib as I've changed some of the (internal) function names, as a test I used the RemoveLines function.

New: TF_FileOrVar (suggestions? I could perhaps also check if TextFile has contents to determine if it is a var, if it is empty it is a file)

The code marked in red could probably be condensed a bit

; script for testing & feedback so I can upgrade TF.AHK to also work with strings
F=
(join`n
!1bla
2bla
3bla
4bla
5bla
6bla
7bla
8bla
9bla
0bla
)
FileDelete, testfile.txt
FileAppend, %f%, testfile.txt

TXT_RemoveLines("testfile.txt", "2+2") ; will process testfile.txt and create testfile_copy.txt
;TXT_RemoveLines("!testfile.txt", "2+2") ; will process testfile.txt and overwrite it
;MsgBox % TXT_RemoveLines(F, "2+2") ; will process the var F and return var, no files will be created

TXT_RemoveLines(TextFile, StartLine = 1, EndLine = 0) ; HugoV
	{
	 [color=red]OW:=TF_FileOrVar(TextFile) ; find out if it is a file, if so find out to overwrite or not, or is it a variable
	 If (OW = 0) or (OW = 1)
		{
	 	 TextFile := (SubStr(TextFile,1,1)="!") ? (SubStr(TextFile,2)) : TextFile
		 FileRead, Str, %TextFile%
		}
	 Else
	    {
		 Str:=TextFile
		 TextFile= ; free memory because TextFile is a var
		} [/color]
     TXT_MatchList:=__MakeMatchList_(Str, StartLine, EndLine) ; create MatchList
	 Loop, Parse, Str, `n, `r
		{
         If A_Index in %TXT_MatchList%
            Continue
         Else
            OutPut .= A_LoopField "`n"
		}
	 Return (OW = 1) ? __OverWrite_(TextFile, Output) : (OW = 0) ? __MakeCopy_(TextFile, Output) : Output
	}

TF_FileOrVar(byref TextFile) ; HugoV, to determine if VAR or FILE is passed to TF
	{
	OW=0 ; default setting: asume it is a file and create textfile_copy
    If (SubStr(TextFile,1,1)="!") ; first we check for "overwrite" 
		{
		 TextFile:=SubStr(TextFile,2)
		 OW=1 ; overwrite file (if it is a file)
		} 
	IfNotExist, %TextFile%     ; now we can check if the file exists
		 {
		  If (OW=1) ; the variable started with a ! so we need to put it back because it is variable not a file
			TextFile:= "!" . TextFile
		  OW=2 ; no file, so it is var
		 } 
	 Return OW
	}

; YOU CAN IGNORE THE REST PURELY INCLUDED AS NOT TO CONFLICT WITH TF.AHK IN LIB
	
; OverWrite TextFile by Heresy / Hugov
__OverWrite_(File, String, TrimTrailing = 1, CreateNewFile = 0)
	{ 
	 IfNotExist, % File ; check if file Exist, if not return otherwise it would create an empty file. Thanks for the idea Murp|e
	 	{
	 	If (CreateNewFile = 0) ; CreateNewFile used for TF_SplitFileBy*, 
	 		Return
		}
	 If (TrimTrailing = 1)
		 StringTrimRight, String, String, 1 ; remove trailing `n
	 SplitPath, File,, Dir, Ext, Name
	 If (Dir = "") ; if Dir is empty TextFile & script are in same directory
		Dir := A_ScriptDir
	 IfExist, % Dir "\backup" ; if there is a backup dir, copy original file there
		FileCopy, % Dir "\" Name "." Ext, % Dir "\backup\" Name ".bak", 1
	 FileDelete, % Dir "\" Name "." Ext
	 FileAppend, %String%, % Dir "\" Name "." Ext
	 Return Errorlevel ? False : True
	}

; Make textfile_copy by Heresy / Hugov
__MakeCopy_(File, String, TrimTrailing = 1)
	{  
	 IfNotExist, % File ; check if file Exist, if not return otherwise it would create an empty file. Thanks for the idea Murp|e
		Return
	 If (TrimTrailing = 1)
		 StringTrimRight, String, String, 1 ; remove trailing `n
	SplitPath, File,, Dir, Ext, Name
	 If (Dir = "") ; if Dir is empty TextFile & script are in same directory
		Dir := A_ScriptDir
	 IfExist, % Dir "\backup" ; if there is a backup dir, copy original file there
		FileCopy, % Dir "\" Name "_copy." Ext, % Dir "\backup\" Name "_copy.bak", 1
	 FileDelete, % Dir "\" Name "_copy." Ext
	 FileAppend, %String%, % Dir "\" Name "_copy." Ext
	 Return Errorlevel ? False : True
}

	
__MakeMatchList_(TextFile, Start = 1, End = 0)
	{
 	 TXT_MatchList= ; just to be sure
	 If (Start = 0 or Start = "")
		Start = 1
 	 ; Option #1
	 ; StartLine has + character indicating startline + incremental processing. 
	 ; EndLine will be used
	 ; Make TXT_MatchList
    
	 IfInString, Start, + 
		{
		 If (End = 0 or End = "")
			End := _TXT_CountLines(TextFile)
		 	 StringSplit, Section, Start, `, ; we need to create a new "TXT_MatchList" so we split by ,
		 Loop, %Section0%
			{
			 StringSplit, SectionLines, Section%A_Index%, `+
			 LoopSection:=End + 1 - SectionLines1
			 Counter=0
	         TXT_MatchList .= SectionLines1 ","
			 Loop, %LoopSection%
				{
				 If (A_Index >= End) ; 
					Break
				 If (Counter = (SectionLines2-1)) ; counter is smaller than the incremental value so skip
					{
					 TXT_MatchList .= (SectionLines1 + A_Index) ","
					 Counter=0
					}
				 Else
					Counter++
				}
			}
		 StringTrimRight, TXT_MatchList, TXT_MatchList, 1 ; remove trailing , 
		 Return TXT_MatchList
		}

	 ; Option #2
	 ; StartLine has - character indicating from-to, COULD be multiple sections. 
	 ; EndLine will be ignored
	 ; Make TXT_MatchList

	 IfInString, Start, `-
		{
		 StringSplit, Section, Start, `, ; we need to create a new "TXT_MatchList" so we split by ,
		 Loop, %Section0%
			{
			 StringSplit, SectionLines, Section%A_Index%, `-
			 LoopSection:=SectionLines2 + 1 - SectionLines1
			 Loop, %LoopSection%
				{
				 TXT_MatchList .= (SectionLines1 - 1 + A_Index) ","
				}
			}
		 StringTrimRight, TXT_MatchList, TXT_MatchList, 1 ; remove trailing ,
		 Return TXT_MatchList
		}

	 ; Option #3
	 ; StartLine has comma indicating multiple lines. 
	 ; EndLine will be ignored
	 IfInString, Start, `,
		{
		 TXT_MatchList:=Start
		 Return TXT_MatchList
		}

	 ; Option #3
	 ; parameters passed on as StartLine, EndLine. 
	 ; Make TXT_MatchList from StartLine to EndLine

	 If (End = 0 or End = "") ; determine nr of lines
		End:=_TXT_CountLines(TextFile)
	 LoopTimes:=End-Start
	 Loop, %LoopTimes%
		{	
		 TXT_MatchList .= (Start - 1 + A_Index) ","
		}
	 TXT_MatchList .= End ","
	 StringTrimRight, TXT_MatchList, TXT_MatchList, 1 ; remove trailing ,
	 Return TXT_MatchList
	}

_TXT_CountLines(Str) ; was TotalLines in v1
	{ 
	 StringReplace, Str, Str, `n, `n, UseErrorLevel
	 Return ErrorLevel+1
	}
Test reports and suggestions welcome

  • Guests
  • Last active:
  • Joined: --
can you tell me how to read backwords ?

eg
1





9

i want to read line 9 and then check if line above it is blank , if yes ,then check the line above it and if its blank then check the line above it and so on untill it finds a non blank line.

SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
@guest: assuming it is a file in two stages with the current TF ahk lib:
- TF_Removeblanklines
- and then depending on what you want TF_Tail OR TF_Reverselines and read the firstline

Alternatively use readLine - Reads specified line contents from a variable
<!-- m -->http://www.autohotke...pic.php?t=26383<!-- m --> but before reading it use the example in the stringreplace doc to remove blank lines from the var first.

  • Guests
  • Last active:
  • Joined: --
why this doesnt work
loop
(
 TF_Tail(F,1)
  x := 1
 var := TF_ReadLines(F,%x%,%x%)
  x--
   if ( var != "")
	   break
	   )


  • Guests
  • Last active:
  • Joined: --
this doesnt work too
var := TF_ReadLines(F,x,x) how to pass numerical values in this function through variables


F = C:\test.txt
loop
{
 x := TF_tail(F,1)
 msgbox % x
 var := TF_ReadLines(F,x,x)
  x--
   if ( var != "")
     {
	  msgbox % var
      break
	 }
      }


SoLong&Thx4AllTheFish
  • Members
  • 4999 posts
  • Last active:
  • Joined: 27 May 2007
The TF_Tail command returns the last line(s) with a `n character at the end so X is not 9 but 9`n which makes it an illegal parameter.

Also your logic might be flawed, you read the last line into X which may be 9 for example, now you pass on 9 to TF_Readlines which is LINE9 so if the last line contains 1234 it would read the 1234th line in the file which is probably not what you want:?:

If you just want to read line X you can try the AHK Command FileReadLine.

Edit: You can use StringTrimRight to remove the trailing `n before you continue does this work for you?

test=
(
1
2
3
4
5
6
7

8

9
)
FileDelete, MyTest.txt
FileAppend, %test%, MyTest.txt
F = MyTest.txt

loop
{
 x := TF_Tail(F,1)
 ;msgbox % x "."
 StringTrimRight, x, x, 1 ; remove trailing `n
 var := TF_ReadLines(F,x,x)
  x--
   if ( var != "")
     {
     msgbox % var
      break
    }
  }
  
Esc::ExitApp