Repository: hi5/TF Branch: master Commit: f31a9c24167d Files: 3 Total size: 110.6 KB Directory structure: gitextract_bq5uzlh1/ ├── license.txt ├── readme.md └── tf.ahk ================================================ FILE CONTENTS ================================================ ================================================ FILE: license.txt ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ================================================ FILE: readme.md ================================================ # TF: Textfile & String Library for AutoHotkey [lib] - v3.8 __A "Swiss Army Knife" library for Text (files)__ ## Introduction As the name suggest this is an AutoHotkey (AHK) Library with a number of functions to "manipulate" **text**, both **files** such as \*.txt, \*.ahk, \*.html, \*.css etc AND **Strings** (or variables). For example you can delete specific lines, replace words or specific lines, number lines, remove or insert columns of text, etc. See the list of functions below for a complete overview. It is **not** useful for binary files or data such as MS Office files, PDFs, EXEcutables, images etc. (Tip: search the AHK forum for "binread" to find some pointers on how to read, write and "edit" binary files.) ## Functions 1. [TF](#TF) 2. [TF_Save](#TF_Save) 3. [TF_CountLines](#TF_CountLines) 4. [TF_Count](#TF_Count) *1 5. [TF_ReadLines](#TF_ReadLines) 6. [TF_Tail](#TF_Tail) 7. [TF_Replace](#TF_Replace) 8. [TF_ReplaceInLines](#TF_ReplaceInLines) 9. [TF_RegExReplace](#TF_RegExReplace) 10. [TF_RegExReplaceInLines](#TF_RegExReplaceInLines) 11. [TF_RemoveLines](#TF_RemoveLines) 12. [TF_RemoveBlankLines](#TF_RemoveBlankLines) 13. [TF_RemoveDuplicateLines](#TF_RemoveDuplicateLines) 14. [TF_InsertLine](#TF_InsertLine) 15. [TF_ReplaceLine](#TF_ReplaceLine) 16. [TF_InsertPrefix](#TF_InsertPrefix) 17. [TF_InsertSuffix](#TF_InsertSuffix) 18. [TF_TrimLeft](#TF_TrimLeft) 19. [TF_TrimRight](#TF_TrimRight) 20. [TF_AlignLeft](#TF_AlignLeft) 21. [TF_AlignCenter](#TF_AlignCenter) 22. [TF_AlignRight](#TF_AlignRight) 23. [TF_LineNumber](#TF_LineNumber) 24. [TF_ConCat](#TF_ConCat) 25. [TF_ColGet](#TF_ColGet) 26. [TF_ColPut](#TF_ColPut) 27. [TF_ColCut](#TF_ColCut) 28. [TF_ReverseLines](#TF_ReverseLines) 29. [TF_Find](#TF_Find) (can be used as basic grep) 30. [TF_SplitFileByLines](#TF_SplitFileByLines) 31. [TF_SplitFileByText](#TF_SplitFileByText) 32. [TF_Merge](#TF_Merge) *2 33. [TF_Prepend](#TF_Prepend) *2 34. [TF_Append](#TF_Append) *2 35. [TF_Wrap](#TF_Wrap) 36. [TF_WhiteSpace](#TF_WhiteSpace) 37. [TF_Substract](#TF_Substract) 38. [TF_RangeReplace](#TF_RangeReplace) 39. [TF_MakeFile](#TF_MakeFile) 40. [TF_Tab2Spaces](#TF_Tab2Spaces) 41. [TF_Spaces2Tab](#TF_Spaces2Tab) 42. [TF_Sort](#TF_Sort) 43. [TF_Join](#TF_Join) **Notes** 1. TF_Count does not support files and only works with variables. 2. TF_Merge, TF_Prepend, TF_Append currently do not support variables and only work with FILES. **Concept** It is important to understand a few basic concepts before you start working with the TF library: - If you pass on a file to a TF function the output will generally be a file (there are a few exceptions). By default it writes the output to a COPY of the input file, leaving the original input file intact. - You **can** overwrite the input file by using a ! as prefix. See "Quick intro to Parameters" and "Textfile and the ! Prefix" below for more details. - If you pass on a variable to a TF function the returned output will also be a variable. - Most TF Functions allow you to work on specific lines or sections of lines. - TF "knows" if something is a file or a variable, even if the variable passed on to TF is meant to represent a file. (This is done in the helper function TF_GetData for those interested). To understand how to work with **files and variables** please read the "Textfile and the ! Prefix" and "Files & Variables" sections below. **File encoding, codepage** If you experience TF is changing the file encoding (codepage) try to set the correct file encoding at the top of your script (or at least before you call a TF function) using the following AutoHotkey command: http://ahkscript.org/docs/commands/FileEncoding.htm Please note, there is no way to determine the file encoding 100% accurately, even if a file contains BOM. See the discussion about this topic and possibly useful additional functions at the AutoHotkey forum http://www.autohotkey.com/board/topic/95986-filegetencoding-filegetformat/ (The result of these functions are simply a best guess assuming UTF-8 more common when BOM - https://en.wikipedia.org/wiki/Byte_Order_Mark - is missing). ## How to "install" / use You can either place TF.ahk in your LIB directory (see [http://ahkscript.org/docs/Functions.htm#lib](http://ahkscript.org/docs/Functions.htm#lib)) or use #include (see [http://ahkscript.org/docs/commands/_Include.htm](http://ahkscript.org/docs/commands/_Include.htm)) You can find examples of most functions in the "example script" here [http://www.autohotkey.com/forum/viewtopic.php?p=280363#280363](http://www.autohotkey.com/forum/viewtopic.php?p=280363#280363) **Note:** Because most of these functions operate on a line by line basis they WILL be slower compared to a function or script which could operate on an entire file or variable at once. Keep this in mind if you need to process many files/variables or very large files/variables in case speed is an issue. ## Quick intro to Parameters Almost all functions accept the following basic parameters:
Parameter Meaning
Text The Filename (may include (absolute) path) to read from and save to (for all functions that write an output file).
Note: by default a filename_copy will be created, use the ! prefix if you want to OverWrite the TextFile (e.g. the source file)
As of v3 "Text" can also be a variable or indeed text directly passed on to the function.
See Textfile and the ! Prefix.
! Prefix If Text starts with ! (eg: "!c:\sample.txt") it will overwrite the text file, otherwise it will save the new file to a copy of the text file eg: Filename_copy.txt (All functions, apart from reading functions because there is no output file)
Tip: you can use concatenation to add the !, e.g. "!" . "Filename.txt", see the examples in the AHK thread.
Note: If Text is a variable, it can start with a ! as TF will detect automatically that it is not a file and will therefore not create a file but return the altered variable instead.
See Textfile and the ! Prefix.
Lines Number of lines to read
StartLine Start of Range (Almost all).
See (StartLine, Endline) Syntax.
EndLine End of Range (Almost all).
See (StartLine, Endline) Syntax.
SearchText Text to Find (Find / Replace functions)
ReplaceText Text to Replace (Find / Replace functions)
**Notes** 1. Many functions also have specific parameters, see the description of each function below. 2. **Backup files:** If a subdirectory "backup" is present in the directory of TextFile a backup is made before overwriting the original file (both for file.txt and file_copy.txt) with the BAK extension 3. You can find examples of most functions in the "example script" here [http://www.autohotkey.com/forum/viewtopic.php?p=280363#280363](http://www.autohotkey.com/forum/viewtopic.php?p=280363#280363) ### (StartLine, Endline) Syntax You can pass on multiple lines (sections) by using the StartLine parameter. Examples: - (5) ; start from line 5 to the end (StartLine) - (5, 15) ; Section: lines 5 to 15 (StartLine, EndLine) - ("5,13,45,67", 135) ; Specific lines: 5,13,45,67, ignore 135 ("StartLine", Endline - **EndLine value is ignored**) - ("5-13,45-51", 135) ; Multiple sections of lines: 5 to 13, 45 to 51 ignore 135 ("StartLine", Endline - **EndLine value is ignored**) Incremental (EndLine will **not** be ignored) in the following cases: - ("2+3", 150) ; start with line 2, increment 3 up-to line 150 so 2,5,8,11,14 etc - ("5+15") ; start with line 5, increment 15 until end of file so 5,20,35 etc Negative Startline - A Negative startline value makes a TF function operate on the last X lines. - TF_ColGet and TF_ColPut accept negative StartColumn parameter. This can be used to "Get" or "Put" text in the x-th "column" from the right ### Textfile and the ! Prefix Valid examples for using a Textfile: ```autohotkey TF_("file.txt", .... ; Process file.txt and write output to file_copy.txt F=file.txt ; ; Note how F is a variable, but AHK/TF will see it is meant to represent file.txt and write output to file_copy.txt TF_(F, .... ; Process file.txt and write output to file_copy.txt TF_("!file.txt", .... ; Process file.txt and overwrite file.txt F=file.txt TF_("!" . F, .... ; Process file.txt and overwrite file.txt F=!file.txt TF_(F, .... ; Process file.txt and overwrite file.txt In a Loop, FilePattern: TF_(A_LoopFileName, .... ; Process file and write output to file_copy TF_("!" . A_LoopFileName, .... ; Process file and overwrite file Loop, *.txt { TF_(A_LoopFileName, .... ; Process file and write output to file_copy } ``` If you want to use multiple TF functions on a single file it is advised to use the ! Prefix ```autohotkey F=!file.txt TF_RemoveBlankLines(F) ; remove all empty lines from file.txt and overwrite original file.txt TF_LineNumber(F) ; add linenumbers to all lines and overwrite original file.txt TF_Replace(F, "this", "that") ; Replace the word "this" with "that" and overwrite original file.txt ; So the original file.txt has undergone three changes ``` **Files & Variables (v3+)** You can use TF functions directly on files as well as variables. Below you will find some easy examples. **Introduced in v3: TF()** In order to save you the trouble of using a fileread to read a file into a variable and proceed to use various TF functions there is the TF() Function. ```autohotkey TF("pathtofile", CreateGlobalVar="T") ``` By default it reads the contents of the file in a global variable named **t** and returns it for further processing. By default it creates variable **t** if a variable name is **omitted** so if you do not like to use **t** you can use anything you like. It is NOT mandatory to use TF(), you are welcome to use a fileread as well, TF() is merely added for convenience as we will see in the examples below. TF() doesn't suddenly make the TF library "not standard compliant" as some seem to think as it only creates a global variable if you use the TF() function. **Repeat:** You only have to use TF() if you want to read a file into a variable and use it on multiple TF_\* Functions but it is NOT required. See also [TF Lib Errors](#tf-lib-errors) below. **TF() Examples:** ```autohotkey TF("file.txt") ; will create global var t TF("file.txt", "MyVar") ; will create global var MyVar ``` **Examples on how to use files & variables with TF:** ```autohotkey #Include tf.ahk TestFile= ; create variable (join`r`n 1 Hi this 2 a test variable 3 to demonstrate 4 how to 5 use this 6 new version 7 of TF.AHK ) FileDelete, TestFile.txt FileAppend, %TestFile%, TestFile.txt ; create file F=TestFile.txt ; just a shorthand code for TextFile.txt, so when ; we are using 'F' below we are still passing on a TextFile, not a variable! ; pass on file, read lines 5 to end of file: MsgBox % "From File 1:`n" TF_ReadLines("TestFile.txt",5) MsgBox % "From File 2:`n" TF_ReadLines(F,5) ; same ; pass on variable, read lines 1 to 5 MsgBox % "From Variable 1:`n" TF_ReadLines(TestFile,"1-5") MsgBox % "From Variable 2:`n" TF_ReadLines("Hi`nthis`nis`na`ntest`nvariable`nfor`ntesting",1,3) ; pass on string ; Examples using TF(): (it will save you a FileRead if you want to work with Variables) TF("TestFile.txt") ; read file, create global var t t:=TF_ReadLines(t,5) ; pass on global var t created by TF(), read lines 5 to end of file, assign result to t MsgBox % "TF(), example 1:`n" t TF("TestFile.txt", "MyVar") ; read file, create global var MyVar MyVar:=TF_ReadLines(MyVar,5) ; pass on global var MyVar created by TF(), read lines 5 to end of file, assign result to MyVar MsgBox % "TF(), example 2:`n" MyVar ; Note how we can use TF() here t:=TF_ReadLines(TF("TestFile.txt"),5) ; pass on global var t created by TF(), read lines 5 to end of file, assign result to t MsgBox % "TF(), example 3:`n" t MyVar:=TF_ReadLines(TF("TestFile.txt","MyVar"),5) ; pass on global var t created by TF(), read lines 5 to end of file, assign result to t MsgBox % "TF(), example 4:`n" MyVar t:=TF_ReadLines(TF(F),5) ; pass on global var t created by TF(), read lines 5 to end of file, assign result to t t:=TF_ReverseLines(t,5) ; pass on global var t created by TF(), reverse lines, assign result to t MsgBox % "TF(), example 5:`n" t ; Work directly with the clipboard or another other variable Clipboard=Line 1`nLine 2`nLine 3`nLine 4`nLine 5`nLine 6`nLine 7`nLine 8 Clipboard:=TF_RemoveLines(Clipboard, 3, 6) ; remove lines 3 to 6 MsgBox % "Clipboard, example 6:`n" Clipboard ``` **Note** TF_Merge, TF_Prepend, TF_Append currently do not support variables and only work with FILES. **Common mistake(s):** ```autohotkey MyVar:=TF_ReadLines("TestFile.txt",5) ; this is wrong. It is AN INCORRECT EXAMPLE! ``` The example above is incorrect: You pass on a file so the output is testfile_copy.txt. In this case nothing meaningful is assigned to the variable MyVar. Correct would be: ```autohotkey MyVar:=TF_ReadLines(MyVar,5) ; this is OK MyVar:=TF_ReadLines(TF("TestFile.txt","MyVar"),5) ; this is OK ``` -------------------------------------------------------------------------- # Functions and Examples **Note:** Some of these functions are very similar, but they are included in the library for ease of use ... You can find examples of most functions in the "example script" here [http://www.autohotkey.com/forum/viewtopic.php?p=280363#280363](http://www.autohotkey.com/forum/viewtopic.php?p=280363#280363) **TF(TextFile, CreateGlobalVar="T")** - Purpose: Read contents of file to create global variable, **T** by default. - Parameters: TextFile, CreateGlobalVar (=preferred name of global variable) - Credits: See TF thread & discussion http://www.autohotkey.com/forum/viewtopic.php?p=313120#313120 Note: see background info and examples above at [Files and Variables](#FilesAndVariables). **TF_CountLines(Text)** - Purpose: Returns the number of lines in a file or variable - Parameters: Text - Credits: SKAN ```autohotkey MsgBox % TF_CountLines("File.txt") ; show the number of lines of file in a MsgBox Lines:=TF_CountLines("File.txt") ; store the number of lines of file in a variable ``` **TF_Count(String, Char)** - Purpose: Count the number of occurrence of Char using StringReplace - Parameters: String, Char Notes: do **not** use it to count lines (using `n) because it will return an incorrect value, use TF_CountLines for counting lines. TF_Count does not support files and only works with variables. ```autohotkey MsgBox % TF_Count("Hello this is an example", "i") ; count how many i's there are in the string ``` **TF_ReadLines(Text, StartLine = 1, EndLine = 0, RemoveTrailing = 0)** - Purpose: Return the specified lines, can be used to read sections of a file or variable. - Parameters: Text, StartLine, EndLine Note: by default it will add a newline character to the last line, so if you want to append new data you don't have to start it with a newline char. If you don't want that use RemoveTrailing = 1. ```autohotkey MsgBox % TF_ReadLines("File.txt",5) ; Read lines 5 to end of file, show result in a MsgBox Lines:=TF_ReadLines("File.txt",5) ; Read lines 5 to end of file, store result in variable MsgBox % TF_ReadLines("File.txt",5,0,1) ; 0 for end line indicates until end of file, remove trailing empty line. ``` **TF_Tail(Text, Lines = 1, RemoveTrailing = 0, ReturnEmpty = 1)** - Purpose: Read last X lines from file or variable - Parameters: Text, Lines, RemoveTrailing (0 or 1), ReturnEmpty (0 or 1) - Credits: incl. ideas from Tuncay Notes: 1. Lines can be a negative number: -1 will get the second to last line. If you use a negative number it will ALWAYS retrieve a SINGLE line 2. By default TF_Tail will return empty lines, if you don't want that use ReturnEmpty = 0 3. By default TF_Tail will add a newline character to the last line, so if you want to append new data to the returned data you don't have to start it with a newline char. If you don't want that use RemoveTrailing = 1 ```autohotkey MsgBox % TF_Tail("File.txt", 3) ; get the last three lines MsgBox % TF_Tail("File.txt", -2) ; get second to last line, negative values only return one line MsgBox % TF_Tail("File.txt", 5, 0, 0) ; return the last five lines, with trailing new line and excluding empty lines ``` **TF_Replace(Text, SearchText, Replacement="")** - Purpose: Find and Replace text in entire file (using StringReplace) - Parameters: Text, SearchText, Replacement ```autohotkey TF_Replace("File.txt","key","lock") ; pass on a file, replace the word "key" with "lock" in file_copy.txt ``` **TF_ReplaceInLines(Text, StartLine = 1, EndLine = 0, SearchText = "", ReplaceText = "")** - Purpose: Find and Replace text on specific lines (using StringReplace) - Parameters: Text, StartLine, EndLine, SearchText, ReplaceText ```autohotkey TF_ReplaceInLines("!File.txt","1,3,9","","key","lock") ; update source file, replace "key" with "lock" in lines 1, 3 and 9 ``` **TF_RegExReplace(Text, NeedleRegEx = "", Replacement = "")** - Purpose: Find and Replace text in entire file (using RegExReplace) - Parameters: Text, NeedleRegEx, Replacement ```autohotkey TF_RegExReplace("File.txt","im)^(.*)$","[$1]") ; pass on a file, wrap all lines in [] ``` **TF_RegExReplaceInLines(Text, StartLine = 1, EndLine = 0, NeedleRegEx= "", Replacement = "")** - Purpose: Find and Replace text in specific lines (using RegExReplace) - Parameters: Text, StartLine, EndLine, NeedleRegEx, Replacement ```autohotkey TF_RegExReplaceInLines("File.txt",3,8," [a-z]{3} "," lock ") ; replace any three letter word with "lock" in lines 3 to 8 ``` **TF_RemoveLines(Text, StartLine = 1, EndLine = 0)** - Purpose: Remove specified lines from file - Parameters: Text, StartLine, EndLine ```autohotkey TF_RemoveLines("File.txt", 5, 10) ; remove lines 5 to 10 from file ``` Note: If you pass on a negative value for StartLine, example TF_RemoveLines(Text, -5, .... it will remove these lines from the end of Text, so -5 will remove the last five lines. The EndLine parameter is ignored. **TF_RemoveBlankLines(Text, StartLine = 1, EndLine = 0)** - Purpose: Remove blank lines from file (in specified section) - Parameters: Text, StartLine, EndLine Note: also removes lines with only tabs & spaces e.g. "white space" ```autohotkey TF_RemoveBlankLines("File.txt") ; remove blanklines in entire file ``` **TF_RemoveDuplicateLines(Text, StartLine = 1, Endline = 0, Consecutive= 0, CaseSensitive = false)** - Purpose: Remove duplicate lines, optionally you can specify if they need to be Consecutive and / or Case sensitive - Parameters: Text, StartLine, EndLine, Consecutive (0 or 1), CaseSensitive (true or false) ```autohotkey TF_RemoveDuplicateLines("File.txt","","",1,false) ; remove only Consecutive duplicate lines ``` **TF_InsertLine(Text, StartLine = 1, Endline = 0, InsertText = "")** - Purpose: Insert text in specified lines - Parameters: Text, StartLine, Endline, InsertText ```autohotkey TF_InsertLine("File.txt","2,4,9",5,"---") ; insert --- in lines 2 4 and 9. 5 is endline will be ignored ``` **TF_ReplaceLine(Text, StartLine = 1, Endline = 0, ReplaceText = "")** - Purpose: Replace specified lines with new text - Parameters: Text, StartLine, Endline, ReplaceText ```autohotkey TF_ReplaceLine("File.txt","1+3",8,"---") ; replace lines 1 4 and 7. 8 is end line so no more lines are processed after ``` **TF_InsertPrefix(Text, StartLine = 1, EndLine = 0, Text = "")** - Purpose: Insert a text at the BEGINNING of each of the specified lines - Parameters: Text, StartLine, Endline, Text ```autohotkey TF_InsertPrefix("File.txt",5,8, "Hello ") ; Prefix Hello in lines 5 to 8 ``` **TF_InsertSuffix(Text, StartLine = 1, EndLine = 0 , Text = "")** - Purpose: Append a text at the END of each of the specified lines - Parameters: Text, StartLine, Endline, Text ```autohotkey TF_InsertSuffix("File.txt","2-4,6-9","", " Hello") ; Suffix Hello in lines 2 to 4 and 6 to 9 ``` **TF_TrimLeft(Text, StartLine = 1, EndLine = 0, Count = 1)** - Purpose: Trim number of specified columns from specified lines - Parameters: Text, StartLine, Endline, Text, Count ```autohotkey TF_TrimLeft("File.txt","","",25) ; Trim Left 25 Characters of all lines ``` **TF_TrimRight(Text, StartLine = 1, EndLine = 0, Count = 1)** - Purpose: Trim number of specified columns from specified lines - Parameters: Text, StartLine, Endline, Text, Count ```autohotkey TF_TrimRight("File.txt","4,6,8","",45) ; Trim Right 45 Characters in lines 4, 6 and 8 ``` **TF_AlignLeft(Text, StartLine = 1, EndLine = 0, Columns = 80, Padding = 0)** - Purpose: Align lines according to number of specified columns - Parameters: Text, StartLine, Endline, Columns, Padding - incl. ideas from SKAN Note: Using the Align functions will not take into account any leading or trailing spaces a line had BEFORE processing. So all white space before and after the text is removed before the text is aligned. ~~~~ Padding = 0 Remove trailing white space Padding = 1 Keep trailing white space ~~~~ ```autohotkey TF_AlignLeft("File.txt","","",90, 1) ; AlignLeft all lines, keep trailing white space ``` **TF_AlignCenter(Text, StartLine = 1, EndLine = 0, Columns = 80, Padding = 0)** - Purpose: Align lines according to number of specified columns - Parameters: Text, Columns, StartLine, Endline, Text - uses some of SKAN functions Note: Using the Align functions will not take into account any leading or trailing spaces a line had BEFORE processing. So all white space before and after the text is removed before the text is aligned. ~~~~ Skip = 0 process empty lines, fill with spaces Skip = 1 skip empty lines, do not fill with spaces ~~~~ ```autohotkey TF_AlignCenter("File.txt","","",150, 1) ; AlignCenter, all lines skip empty lines, do not fill with spaces ``` **TF_AlignRight(Text, StartLine = 1, EndLine = 0, Columns = 80, Skip = 0)** - Purpose: Align lines according to number of specified columns - Parameters: Text, Columns, StartLine, Endline, Skip (0 or 1) - uses some of SKAN functions Note: Using the Align functions will not take into account any leading or trailing spaces a line had BEFORE processing. So all white space before and after the text is removed before the text is aligned. ~~~~ Skip = 0 process empty lines, fill with spaces Skip = 1 skip empty lines, do not fill with spaces ~~~~ ```autohotkey TF_AlignRight("File.txt","","", 190, 0) ; AlignRight, all lines, do not skip empty lines fill them with spaces ``` **TF_LineNumber(Text, Leading = 0, Restart = 0, Char = 0)** - Purpose: Insert line numbers before each line - Parameters: Text, Leading, Restart, Char - Credits: incl. ideas from ribbet.1 ~~~~ Leading = 0 No padding with leading zeros Leading >= 1 Include padding with leading zeros (001 v 1) Restart = restart counter after X lines (starting again at 1) Char = character to use for leading/padding. Default 0, but can be any character. Tip: use a space. ~~~~ ```autohotkey TF_LineNumber("File.txt",1,15,A_Space) ; Add linenumbers, padding with spaces, linenumbers are aligned right because of space ``` **TF_ConCat(FirstTextFile, SecondTextFile, OutputFile, Blanks = 0, FirstPadMargin = 0, SecondPadMargin = 0)** - Purpose: Join Text files side by side (line1-from-file1 line1-from-file2 newline line2-from-file1 line2-from-file2 newline etc) - Parameters: FirstTextFile, SecondTextFile, OutputFile, Blanks, FirstPadMargin, SecondPadMargin Based on: CONCATenate text files, ftp://garbo.uwasa.fi/pc/ts/tsfltc22.zip - Backup: http://www.retroarchive.org/garbo/pc/ts/ With TF_ConCat you can join Text files side by side. Blanks is number of blanks between lines. You can pad blanks the right margin of either of the text files, for this use FirstPadMargin and SecondPadMargin. **TF_ColGet(Text, StartLine = 1, EndLine = 0, StartColumn = 1, EndColumn = 1, Skip = 0)** - Purpose: Get specified columns from text file - Parameters: Text, StartLine, EndLine, StartColumn, EndColumn, Skip (0 or 1) ~~~~ Note: A TAB character is 1 character so for files with TABS the column might not be where you expect it to be skip = 0, DO NOT skip lines shorter then startcolumn position skip = 1, skip lines shorter then startcolumn position TF_ColGet and TF_ColPut accept negative StartColumn parameter. This can be used to "Get" or "Put" text in the x-th "column" from the right ~~~~ ```autohotkey TF_ColGet("File.txt","","",2,13) ; get columns 2 to 13 from all lines, so it removes all other columns from the file or variable ``` **TF_ColPut(Text, Startline = 1, EndLine = 0, StartColumn = 1, Text = "", Skip = 0)** - Purpose: Insert text at specified columns in text file - Parameters: Text, StartLine, EndLine, StartColumn, EndColumn, Skip (0 or 1) Based on: COLPUT.EXE & CUT.EXE, ftp://garbo.uwasa.fi/pc/ts/tsfltc22.zip - Backup: http://www.retroarchive.org/garbo/pc/ts/ ~~~~ Note: A TAB character is 1 character so for files with TABS the column might not be where you expect it to be skip = 0, DO NOT skip lines shorter then startcolumn position skip = 1, skip lines shorter then startcolumn position TF_ColGet and TF_ColPut accept negative StartColumn parameter. This can be used to "Get" or "Put" text in the x-th "column" from the right ~~~~ ```autohotkey TF_ColPut("File.txt","","",5, "|", 0) ; insert | in column 5 of all lines including empty lines (= | will be at column 1) ``` **TF_ColCut(Text, StartLine = 1, EndLine = 0, StartColumn = 1, EndColumn = 1)** - Purpose: Remove specified columns from text file - Parameters: Text, StartLine, EndLine, StartColumn, EndColumn Based on: COLPUT.EXE & CUT.EXE, ftp://garbo.uwasa.fi/pc/ts/tsfltc22.zip ```autohotkey TF_ColCut("File.txt", "2+2", "", 4, 38) ; remove columns 4 to 38 in lines 2 4 6 8 etc ``` **TF_ReverseLines(Text, StartLine = 1, EndLine = 0)** - Purpose: Reverse the order of specified lines - Parameters: Text, StartLine, EndLine Note: Startline parameter can not use specific lines, sections or incremental values here ```autohotkey TF_ReverseLines("File.txt",2,9) ; reverse lines 2 to 9 ``` **TF_Find(Text, StartLine = 1, EndLine = 0, SearchText = "", ReturnFirst = 1, ReturnText = 0)** - Purpose: Find text using RegExMatch, return line(s), text or lines and text - Parameters: Text, StartLine, EndLine, SearchText, ReturnFirst, ReturnText TF_Find(Lines) uses Regular Expressions - This means that if you use certain characters which have a special meaning in a RegEx: **\\.\*?+[{|()\^\$** they must be preceded by a backslash to be seen as literal. For example, **\\.** is a literal period and **\\\\** is a literal backslash. Escaping can be avoided by using **\\Q**...**\\E**. For example: **\\QLiteral Text\\E**. See [http://ahkscript.org/docs/commands/RegExMatch.htm](http://ahkscript.org/docs/commands/RegExMatch.htm) for further information. ~~~~ ReturnFirst = 0 return multiple lines ReturnFirst = 1 return first line only ReturnText = 0 return line numbers only ReturnText = 1 return entire line (text). This simulates a basic grep feature ReturnText = 2 return line numbers + entire line (text). This simulates a basic grep feature ~~~~ ```autohotkey MsgBox % TF_Find("File.txt", "", "", "keys") ; return first line number with keys in it MsgBox % TF_Find("File.txt", "", "", " c[a-z]+s ", 0, 1) ; find all lines with words that start with a c an end with an s ``` **TF_SplitFileByLines(Text, SplitAt, Prefix = "file", Extension = "txt", InFile = 1)** - Purpose: Split a text file in to several others based on number of lines - Parameters: Text, SplitAt (number), Prefix, Extension, InFile (0, 1 or 2) ~~~~ SplitAt = Number of lines (three methods, see below) Prefix . Extension = filenameAUTOINCREMENT.Extension (Example: part_ . txt) InFile = 0 skip line e.g. do not include the actual line in any of the output files InFile = 1 include line IN current file InFile = 2 include line IN next file ~~~~ Note: If you pass on a variable to TF_SplitFileByLines, the array size will be returned as Prefix0 and the array elements as Prefix1, Prefix2 etc similar to the AHK StringSplit command. The Extension parameter is ignored when using variables. Some characters are illegal such as - + @ % & \* _ \\ / [ ] etc to use in Prefix, stick to a-z A-Z. Options for "SplitAt" parameter: ~~~~ a) One numerical value, example TF_SplitFileByLines(Text, "25", .... will split text every 25 lines until the end b) Split at rotating line lengths using a dash "-" as separator, example TF_SplitFileByLines(Text, "5-10-15", .... will split text at 5 10 15 lines, until the end so 5 lines, 10 lines, 15 lines, 5 lines, 10 lines etc c) Split at specific lines using a comma "," as separator, example TF_SplitFileByLines(Text, "5,81,135", .... will split text at lines 5,81,135 until end of file (e.g. last file will be from line 135 until the end) ~~~~ ```autohotkey TF_SplitFileByLines("File.txt", 2, "part", "zec", 1) ; split source file every 2 lines, include 2nd line INFILE ; illustrate use of variables and returned arrays: TF_SplitFileByLines(Variable, 2, "part", "zec", 1) MsgBox % "Array size: " . Part0 . "`n1st array element: " Part1 ``` **TF_SplitFileByText(Text, SplitAt, Prefix = "file", Extension = "txt", InFile = 1)** - Purpose: Split a text file in to several others based on text - Parameters: Text, SplitAt (text, can be RegEx), Prefix, Extension, InFile (0, 1 or 2) ~~~~ SplitAt = Text, can be RegEx Prefix . Extension = filenameAUTOINCREMENT.Extension (Example: part_ . txt) InFile = 0 skip line e.g. do not include the actual line in any of the output files InFile = 1 include line IN current file InFile = 2 include line IN next file ~~~~ Note: If you pass on a variable to TF_SplitFileByLines, the array size will be returned as Prefix0 and the array elements as Prefix1, Prefix2 etc similar to the AHK StringSplit command. The Extension parameter is ignored when using variables. Some characters are illegal such as - + @ % & \* _ \\ / [ ] etc to use in Prefix, stick to a-z A-Z. ```autohotkey TF_SplitFileByText("File.txt", "button", "part", "zec", 1) ; split source file on every line with the word button, include that line INFILE ; illustrate use of variables and returned arrays: TF_SplitFileByText(Variable, "keyboard", "part", "zec", 1) MsgBox % "Array size: " . Part0 . "`n1st array element: " Part1 ``` **TF_Merge(FileList, Separator = "\`n", FileName = "merged.txt")** - Purpose: Merge several files into one - Parameters: FileList, Separator (what to put between two files, newline by default), FileName (name of output file, Prefix with a ! to overwrite target file) Example FileList: ~~~~ FileList= ( file1.txt file2.txt file3.txt ) ~~~~ Note: TF_Merge, TF_Prepend, TF_Append currently do not support variables and only work with FILES. ```autohotkey ; using Loop (files & folders) to create one quickly if you want to merge all TXT files for example: Loop, c:\*.txt FileList .= A_LoopFileFullPath "`n" TF_Merge(FileList) ; will create merged.txt, you can use ! to overwrite an existing file if you want ; using FileSelectFile to select files to merged: (Thanks for asking Vitor, http://www.autohotkey.com/forum/viewtopic.php?p=335329#335329) FileDelete merged.txt ; not required FileList= FileSelectFile, FileList, M 1,,, *.txt ; M allows you to select multiple files while holding down the left ctrl button If (ErrorLevel = 1) or (FileList = "") ExitApp ; no files selected Path:=TF_ReadLines(FileList,1,1,1) ; the first line holds the directory of the selected files, so read path FileList:=TF_RemoveLines(FileList,1,1) ; remove path from filelist FileList:=TF_InsertPrefix(FileList, "", "", Path . "\") ; make sure all files have full paths to file so the are read correctly TF_Merge(FileList) ; will create a file in the current script dir called merged.txt you can also specify another filename, take into account the filedelete merged.txt above ; You could skip the Path:= step above by calling TF_ReadLines directly in TF_InsertPrefix, but you would have to delete the first line AFTER it like so: ;FileList:=TF_InsertPrefix(FileList, "", "", TF_ReadLines(FileList,1,1,1) . "\") ;FileList:=TF_RemoveLines(FileList,1,1) ``` **TF_Prepend(File1, File2)** - Purpose: Prepend file1 to file2 (file2 is changed, uses TF_Merge) - Parameters: File1, File2 Note: TF_Merge, TF_Prepend, TF_Append currently do not support variables and only work with FILES. **TF_Append(File1, File2)** - Purpose: Append file1 to file2 (file2 is changed, uses TF_Merge) - Parameters: File1, File2 Note: TF_Merge, TF_Prepend, TF_Append currently do not support variables and only work with FILES. **TF_Wrap(Text, Columns = 80, AllowBreak = 0, StartLine = 1, EndLine = 0)** - Purpose: Wrap (specified) lines - Parameters: Text, Columns, AllowBreak (0 or 1), StartLine, EndLine ~~~~ AllowBreak = 0 will not "break" words, so it will take into account whole words and not chop them off. AllowBreak = 1 will break words ~~~~ ```autohotkey TF_Wrap("File.txt",60) ; wrap at col 60 ``` **TF_WhiteSpace(Text, RemoveLeading = 1, RemoveTrailing = 1, StartLine = 1, EndLine = 0)** - Purpose: Remove leading and/or trailing whitespace - Parameters: Text, RemoveLeading (0 or 1), RemoveTrailing (0 or 1), StartLine, EndLine ~~~~ RemoveLeading = 0 Do not remove leading white space of lines RemoveLeading = 1 Remove leading white space of lines RemoveTrailing = 0 Do not remove trailing white space of lines RemoveTrailing = 1 Remove trailing white space of lines ~~~~ ```autohotkey TF_WhiteSpace("File.txt", 1, 0, "5-10") ; remove leading and keep trailing whitespace in lines 5 to 10 ``` **TF_Substract(File1, File2, PartialMatch = 0)** - Purpose: Delete lines from file1 in file2 (using StringReplace) - Parameters: File1, File2, PartialMatch (0 or 1) ~~~~ File2: you can use !file2 to overwrite file2 otherwise output is file2_copy.txt PartialMatch = 0 lines from file1 must appear as is, case insensitive PartialMatch = 1 allow for paRTIal match of line PartialMatch = 2 allow for paRTIal match of line, but remove entire line (uses RegEx, new as of v3.4) ~~~~ **TF_RangeReplace(Text, SearchTextBegin, SearchTextEnd, ReplaceText = "", CaseSensitive = "False", KeepBegin = 0, KeepEnd = 0)** - Purpose: A Range Replacement allows you to perform a replacement on text whose beginning and ending remains the same, but whose middle contents might change. - Parameters: SearchTextBegin, SearchTextEnd, ReplaceText, CaseSensitive (True or False), KeepBegin (0 or 1), KeepEnd (0 or 1) Note: Similar to "BK Replace EM" Range Replacement. It is basically an easier shortcut for a more complex RegExp. ~~~~ KeepBegin = 0 Remove SearchTextBegin from file KeepBegin = 1 Do not remove SearchTextBegin from file (saves you the trouble of putting it back in via ReplaceText) KeepEnd = 0 Remove SearchTextEnd from file KeepEnd = 1 Do not remove SearchTextEnd from file (saves you the trouble of putting it back in via ReplaceText) SearchTextBegin = "" e.g. empty means from START of File *1 SearchTextEnd = "" e.g. empty means until END of File *1 ~~~~ \*1 if you pass on empty strings to SearchTextBegin and SearchTextEnd the entire file will replaced with the replacement text. SearchTextBegin/End **can** be on the same line. Remember this LIB mainly operates on a line by line basis. This Function only operates on the FIRST SearchTextBegin to the FIRST SearchTextEnd it finds. ```autohotkey Range=[insert this`ntext for the`nrange replace Text`ntest function] TF_RangeReplace("File.txt", "Create hotkeys for keyboard", "into an EXE file", Range) ``` **TF_MakeFile(Text, Lines = 1, Columns = 1, Fill = " ")** - Purpose: Create file of X lines and Y columns, fill with space or other character(s) - Parameters: TextFile (new file to be created), Lines, Columns, Fill Sometimes you need an "empty" file before you can start adding line numbers or putting data into a file. **TF_Tab2Spaces(Text, TabStop = 4, StartLine = 1, EndLine = 0)** - Purpose: Convert tabs to spaces, shorthand for TF_ReplaceInLines - Parameters: Text, TabStop, StartLine, EndLine - Credits: incl. ideas from infogulch ~~~~ TabStop = number of spaces to replace a TAB with, so 4 means a TAB will be replaced by 4 spaces ~~~~ **TF_Spaces2Tab(Text, TabStop = 4, StartLine = 1, EndLine = 0)** - Purpose: Convert tabs to spaces, shorthand for TF_ReplaceInLines - Parameters: Text, TabStop, StartLine, EndLine - Credits: incl. ideas from infogulch ~~~~ TabStop = number of spaces to replace with a TAB, so 4 means 4 spaces will be replaced by a TAB ~~~~ **TF_Sort(Text, SortOptions = "", StartLine = 1, EndLine = 0)** - Purpose: Sort (section of) TextFile - Parameters: Text, SortOptions, StartLine, EndLine ~~~~ SortOptions: use the SORT options http://ahkscript.org/docs/commands/Sort.htm ~~~~ Note: StartLine can not have multiple sections, increments or multiple lines in this case. When dealing with variables/strings instead of text files the native AHK Sort command is of course more useful. **TF_Join(Text, StartLine = 1, EndLine = 0, SmartJoin = 0, Char = 0)** - Purpose: Join lines (section of) - Parameters: Text, StartLine, EndLine, SmartJoin, Char ~~~~ SmartJoin: Detect if CHAR(s) is/are already present at the end of the line before joining the next, this to prevent unnecessary double spaces for example. Char: character(s) to use between new lines, defaults to a space. To use nothing use "" ~~~~ Note: StartLine can not use increments. It can have multiple sections. **TF_Save(Text, FileName, OverWrite = 1)** - Purpose: To save a variable to a file - Parameters: Text, FileName, OverWrite (O or 1) ~~~~ OverWrite = 0 create filename_copy.ext if filename.ext exists OverWrite = 1 will overwrite filename.ext if filename.ext exists (default) ~~~~ # TF Lib Errors 1. Error when using the ! prefix. The correct syntax is "!file.txt". If you do this !"file.txt" (the ! is not within the quotes it will not be able to read a file) 2. If you pass on a single zero as text ```TF_TrimLeft("0",1,1,3)``` and there is no file with that name ```"0"``` it will shown an error. More as one zero as "text" is OK. # History **History v3.8, 11 December 2020** - Prevent TF_Sort from removing last character from the last line https://github.com/hi5/TF/issues/11 **History v3.7, 16 April 2017** - Added: additional check for passing on just zero/zeros as text to TF functions in TF_GetData() - see v3.6 below - Fix: changed readme.md to fix rendering issue of MD files on GH - https://github.com/hi5/TF/issues/5 **History v3.6, 25 December 2014** - Added: Added additional minor error check in TF_GetData - if "Text" is "false", there is nothing to process so Exit **History v3.5, 2 August 2014** - Changed A_ScriptDir to A_WorkingDir in TF_ReturnOutPut - https://github.com/hi5/TF/issues/1 - Fixed: TF_ColGet negative startcolumn and sections now work correctly **History v3.4, 30 October 2010 - UNRELEASED at the time** - New function: TF_Join: joining lines. - Added: A_ThisFunc to helper function TF_MatchList, this may help with error messages such as: Invalid StartLine parameter (non numerical character) - Function used: A_ThisFunc - Added/Change: New option for StartLine, Negative startline operate on last X lines was already the case for TF_removelines, applies to all TF functions - Added: TF_Substract: Partialmatch = 2 now deletes entire line on partial match, see TF DOC for more info. - Added: TF_ColGet and TF_ColPut now accept negative StartColumn parameter. Can be used to Get or Put text in the xth "column" from the right, see description above - TF_ColCut does **not** support this as you can use TF_TrimRight. - Added: TF_ColGet, TF_ColPut and TF_ColCut can now process multiple columns in one go. Format: CSV or incremental (DO **not** use sections for TF_ColPut due to unexpected end results) - Minor improvements to the documentation - removed TF_FindLines from lib (was already deprecated) **History v3.3, 16 April 2010** - Fixed: If you used variables with any of the replacement functions or tried to remove empty lines from a VARIABLE in the following format: variable:=TF_..(variable,"search","replace") and the searchtext was NOT present in the variable it returned an empty variable (e.g. deleted the contents of "variable"). It affected TF_ReplaceInLines, TF_Replace, TF_RegExReplaceInLines, TF_RegExReplace, TF_RemoveBlankLines, TF_RangeReplace\. The built-in check only worked correctly for FILES and with the introduction of variables in TF 3 this didn't surface during testing. - Fixed: documentation error for TF_Merge (separator and filename where swapped) and added examples on how to use TF_Merge in a Loop and with FileSelectFile **History v3.2, 20 February 2010** - Fixed: TF_AlignRight: due to a bug it didn't work as it should have, it prepended the number of spaces rather than aligning the text at the specified width. - Changed: TF_GetData (helper function) should now avoid unnecessary IfNotExist for files, for scripts with many loops in combination with variables it should improve the speed slightly - Changed: TF_SplitFileByLines: New options for SplitAt, now three methods available, see notes at function description - Changed: TF_RemoveLines: New option for StartLine, if negative value is used it will remove the last X lines from file, see notes at function description **History v3.1, 09 December 2009** - Changed: Rewrite of TF_Find. Can now return multiple lines (like TF_Findlines used to), not only linenumbers but the entire line (text) of found lines so it can be used as a basic grep. Now uses RegExp, see compatibility notes. - Deprecated: TF_FindLines (see change TF_Find). Kept in for backwards compatibility - Updated and expanded documentation with examples and a hopefully "better" introduction highlighting some basic concepts **History v3.0, 27 November 2009** Complete overhaul of library, now accepts files & variables for input and output: - Changed: New parameter for TF_Readlines & TF_Tail: trailing new line now optional - Added: TF_Save, shorthand for filedelete+fileappend - Added: TF_GetData, helper function to determine if a file or a variable is passed on to function - Added: TF() To read a text file in global var, t by default - Credits various ... - Added: TF_ReturnOutput has replaced: Overwrite, MakeCopy and the newly developed ReturnStr - Changed: Complete rewrite of TF_Tail, new options - borrowed bits from Tuncay (Thanks!) - Changed: MakeMatchList: Removed TF_Countlines (one less fileread), Pass on "String" and not a TextFile - Fix: TF_ConCat & TF_MakeFile didn't write output file - same bug as splitby* earlier. **History v2.5 fix, 01 November 2009** - Unreleased, but available on request :-) Note that in 2.4a TF_MakeFile and TF_ConCat do not produce output files, easy to fix if you are determined to use an older version of TF. **History 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) **History v2.4 update, 06 August 2009:** - Added: TF_Sort **History v2.3b update, 03 August 2009:** - Fixed: No output problem for TF_SplitFileBy* functions, "bug" introduced by 2.3a "Built in Check if TextFile actually exists" - TF_RemoveBlankLines check if file has empty empty lines to start with, if not return and do nothing (does not create file_copy identical to file) - TF_RangeReplace same fix as 2.3a **History v2.3a update/bugfix (29 July 2009, HugoV, ribbet.1, Murp|e)** Fixed/Changed: - New features in TF_LineNumber: Restart + Choice of leading/padding character. Thanks for the idea ribbet.1, [http://www.autohotkey.com/forum/viewtopic.php?p=284687#284687](http://www.autohotkey.com/forum/viewtopic.php?p=284687#284687) - Built in Check if TextFile actually exists, to prevent creation of empty file(s). Thanks for the idea Murp|e, [http://www.autohotkey.com/forum/viewtopic.php?p=284649#284649](http://www.autohotkey.com/forum/viewtopic.php?p=284687#284687) - TF_Replace: if SearchText wasn't present in TextFile the function never returned (stuck in endless loop) - TF_ReplaceInLines: if SearchText wasn't present in TextFile simple return an do nothing (faster, does not create file_copy) - TF_RegExReplaceInLines: if NeedleRegEx wasn't present in TextFile simple return an do nothing (faster, does not create file_copy) **History v2.3 (28 July 2009)** - Added: TF_Tab2Spaces - Note: Thanks to infogulch - Added: TF_Spaces2Tab - ditto - Added: TF_RangeReplace - Added: TF_MakeFile Also thanks to Murp|e for pointing out some errors in the documentation (TF_COL\* functions). **History v2.2 (10 July 2009)** - Added: TF_Substract - Added: TF_WhiteSpace - Added: TF_Wrap **History v2.1** - Added: TF_Prepend - Added: TF_Append **History v2.0 (Overhaul by HugoV using TXT lib as starting point)** - Renamed: TF_TotalLines to TF_CountLines (seemed more logical) - Removed: TF_GetCSV, TF_SetCSV to keep the focus on TXT files, CSV requires a different library IMHO (HugoV) - Introduced: _MakeMatchList_ and adjusted TF_ReadLines, TF_RemoveLines, TF_InsertPrefix, TF_InsertSuffix, TF_TrimLeft, TF_TrimRight, TF_ColGet, TF_ColPut, TF_ColCut accordingly (HugoV) - Make a MatchList which is used in various functions (listed above) - Using a MatchList gives greater flexibility so you can process multiple sections of lines in one go avoiding repetitive fileread/append actions - You can pass on multiple lines (sections) If you quote the StartLine parameter. Examples of StartLine, Endline: 5 ; start from line 5 to the end (StartLine) 5, 15 ; lines 5 to 15 (StartLine, EndLine) "5,13,45,67", 135) ; lines 5,13,45,67, ignore 135 ("StartLine", Endline - EndLine value is ignored) "5-13,45-51", 135) ; lines 5 to 13, 45 to 51 ignore 135 ("StartLine", Endline - EndLine value is ignored) - Incremental processing of lines, example startline, endline - endline will not be ignored "2+3", 150 ; start with line 2, increment 3 up-to line 150 so 2,5,8,11,14 etc "5+15" ; start with line 5, increment 15 until end of file so 5,20,35 etc - Introduced: _OverWrite_ & _MakeCopy_ (Heresy / HugoV) - No longer necessary to pass on full path, e.g. "file.txt" works OK now (HugoV) - Reduces size of library by removing repeating code sections for saving Output (Heresy) - Backup files: If a subdirectory "backup" is present in the directory of TextFile a backup is made before overwriting the original file (both for file.txt and file_copy.txt) with the BAK extension (HugoV) - Includes fix to remove trailing \`n added by most functions (HugoV) - Introduced: SetWidth/space by SKAN for TF_Align* Functions http://www.autohotkey.com/forum/viewtopic.php?p=45880#45880 - Added: TF_ReplaceInLines. Similar to TF_Replace - Added: TF_RegExReplaceInLines. Similar to TF_RegExReplace - Added: TF_SplitFileByLines (HugoV) - Added: TF_SplitFileByText (HugoV) - Added: TF_Merge (HugoV) - Added: TF_Find (HugoV, based on example by olegbl) - Added: TF_FindLines (HugoV, based on example by olegbl) - Change: TF_TrimLeft. 1 - it now processes all lines of the TextFile. 2 - you can now omit EndLine e.g. will process until end of file (HugoV) - Change: TF_TrimRight. 1 - it now processes all lines of the TextFile. 2 - you can now omit EndLine e.g. will process until end of file (HugoV) - Change: TF_AlignCenter, TF_AlignLeft, TF_AlignRight. Now use SetWidth/space by SKAN, more reliable also adds spaces to RIGHT side of line - Change: TF_AlignLeft. 1 - you can now use StartLine, EndLine parameters. 2 - StartLine and/or EndLine can be omitted (HugoV) - Change: TF_AlignRight. 1 - you can now use StartLine, EndLine parameters. 2 - StartLine and/or EndLine can be omitted (HugoV) - Change: TF_ReadLines you can now omit EndLine e.g. will read until end of file (HugoV) - Change: TF_RemoveBlankLines you can now use StartLine, EndLine parameters. EndLine can be omitted (HugoV) - Change: TF_InsertLine modified to accommodate line sections and incremental lines. - Change: TF_ReplaceLine modified to accommodate line sections and incremental lines. - Change: TF_RegExReplace no longer returns "Counts" (HugoV) - Change: TF_RemoveDuplicateLines 1 - no longer returns "Removed". 2 - can use start/end line, 3 - no longer uses sort but keeps original order intact, 4 - to methods to check consecutive lines or unique files in file (HugoV) - Change: TF_ColGet, TF_ColPut, TF_ColCut. 1 - order of parameters changed, 2 - now accept Startline, EndLine parameters. (HugoV) - Fixed: TF_RemoveDuplicateLines always produced empty Output file (HugoV) **History prior 2.0 - TXT library (Heresy, HugoV)** - 2008-06-18 : added TF_AlignLeft(), TF_AlignCenter(), TF_AlignRight() (Heresy) - 2008-06-18 : added TF_Tail(), TF_ReverseLines() (HugoV) - 2008-06-17 : added TF_GetCSV(), TF_SetCSV() (Heresy) - 2008-06-17 : added TF_LineNumber(), TF_Concat(), TF_ColGet(), TF_ColPut(), TF_ColCut() (HugoV) - 2008-06-16 : added TF_RegExReplace(), TF_RemoveLines(), TF_TrimLeft(), TF_TrimRight() (Heresy) - 2008-06-15 : added TF_TotalLines(), TF_ReadLines(), TF_RemoveDuplicateLines() (Heresy) ## Credits This library is based on the *Library for Text file manipulation* started by [Heresy](http://www.autohotkey.com/forum/profile.php?mode=viewprofile&u=8193). I have contributed a number of functions to that library, but that version also has some "bugs" which are hopefully resolved in this TF library. Thanks to: Heresy, SKAN! (countlines, setwidth, spaces), Olegbl, (suggestion for find*), infogulch (suggestion for tab \<-\> spaces), Murp|e (suggestions for documentation, check if file exists), ribbet.1 (New features in TF_LineNumber), Tuncay (help with TF() and borrowed ideas for TAIL). ================================================ FILE: tf.ahk ================================================ /* Name : TF: Textfile & String Library for AutoHotkey Version : 3.8 Documentation : https://github.com/hi5/TF AutoHotkey.com: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=576 AutoHotkey.com: http://www.autohotkey.com/forum/topic46195.html (Also for examples) License : see license.txt (GPL 2.0) Credits & History: See documentation at GH above. Structure of most functions: TF_...(Text, other parameters) { ; get the basic data we need for further processing and returning the output: TF_GetData(OW, Text, FileName) ; OW = 0 Copy inputfile ; OW = 1 Overwrite inputfile ; OW = 2 Return variable ; Text : either contents of file or the var that was passed on ; FileName : Used in case OW is 0 or 1 (=file), not used for OW=2 (variable) ; Creates a matchlist for use in Loop below TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; A_ThisFunc useful for debugging your scripts Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { ... } Else { ... } } ; either copy or overwrite file or return variable Return TF_ReturnOutPut(OW, OutPut, FileName, TrimTrailing, CreateNewFile) ; OW 0 or 1 = file ; Output = new content of file to save or variable to return ; FileName ; TrimTrailing: because of the loops used most functions will add trailing newline, this will remove it by default ; CreateNewFile: To create a file that doesn't exist this parameter is needed, only used in few functions } */ TF_CountLines(Text) { TF_GetData(OW, Text, FileName) StringReplace, Text, Text, `n, `n, UseErrorLevel Return ErrorLevel + 1 } TF_ReadLines(Text, StartLine = 1, EndLine = 0, Trailing = 0) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% OutPut .= A_LoopField "`n" Else if (A_Index => EndLine) Break } OW = 2 ; make sure we return variable not process file Return TF_ReturnOutPut(OW, OutPut, FileName, Trailing) } TF_ReplaceInLines(Text, StartLine = 1, EndLine = 0, SearchText = "", ReplaceText = "") { TF_GetData(OW, Text, FileName) IfNotInString, Text, %SearchText% Return Text ; SearchText not in TextFile so return and do nothing, we have to return Text in case of a variable otherwise it would empty the variable contents bug fix 3.3 TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { StringReplace, LoopField, A_LoopField, %SearchText%, %ReplaceText%, All OutPut .= LoopField "`n" } Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_Replace(Text, SearchText, ReplaceText="") { TF_GetData(OW, Text, FileName) IfNotInString, Text, %SearchText% Return Text ; SearchText not in TextFile so return and do nothing, we have to return Text in case of a variable otherwise it would empty the variable contents bug fix 3.3 Loop { StringReplace, Text, Text, %SearchText%, %ReplaceText%, All if (ErrorLevel = 0) ; No more replacements needed. break } Return TF_ReturnOutPut(OW, Text, FileName, 0) } TF_RegExReplaceInLines(Text, StartLine = 1, EndLine = 0, NeedleRegEx = "", Replacement = "") { options:="^[imsxADJUXPS]+\)" ; Hat tip to sinkfaze http://www.autohotkey.com/forum/viewtopic.php?t=60062 If RegExMatch(searchText,options,o) searchText := RegExReplace(searchText,options,(!InStr(o,"m") ? "m$0" : "$0")) Else searchText := "m)" . searchText TF_GetData(OW, Text, FileName) If (RegExMatch(Text, SearchText) < 1) Return Text ; SearchText not in TextFile so return and do nothing, we have to return Text in case of a variable otherwise it would empty the variable contents bug fix 3.3 TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { LoopField := RegExReplace(A_LoopField, NeedleRegEx, Replacement) OutPut .= LoopField "`n" } Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_RegExReplace(Text, NeedleRegEx = "", Replacement = "") { options:="^[imsxADJUXPS]+\)" ; Hat tip to sinkfaze http://www.autohotkey.com/forum/viewtopic.php?t=60062 if RegExMatch(searchText,options,o) searchText := RegExReplace(searchText,options,(!InStr(o,"m") ? "m$0" : "$0")) else searchText := "m)" . searchText TF_GetData(OW, Text, FileName) If (RegExMatch(Text, SearchText) < 1) Return Text ; SearchText not in TextFile so return and do nothing, we have to return Text in case of a variable otherwise it would empty the variable contents bug fix 3.3 Text := RegExReplace(Text, NeedleRegEx, Replacement) Return TF_ReturnOutPut(OW, Text, FileName, 0) } TF_RemoveLines(Text, StartLine = 1, EndLine = 0) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% Continue Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_RemoveBlankLines(Text, StartLine = 1, EndLine = 0) { TF_GetData(OW, Text, FileName) If (RegExMatch(Text, "[\S]+?\r?\n?") < 1) Return Text ; No empty lines so return and do nothing, we have to return Text in case of a variable otherwise it would empty the variable contents bug fix 3.3 TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% OutPut .= (RegExMatch(A_LoopField,"[\S]+?\r?\n?")) ? A_LoopField "`n" : Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_RemoveDuplicateLines(Text, StartLine = 1, Endline = 0, Consecutive = 0, CaseSensitive = false) { TF_GetData(OW, Text, FileName) If (StartLine = "") StartLine = 1 If (Endline = 0 OR Endline = "") EndLine := TF_Count(Text, "`n") + 1 Loop, Parse, Text, `n, `r { If (A_Index < StartLine) Section1 .= A_LoopField "`n" If A_Index between %StartLine% and %Endline% { If (Consecutive = 1) { If (A_LoopField <> PreviousLine) ; method one for consecutive duplicate lines Section2 .= A_LoopField "`n" PreviousLine:=A_LoopField } Else { If !(InStr(SearchForSection2,"__bol__" . A_LoopField . "__eol__",CaseSensitive)) ; not found { SearchForSection2 .= "__bol__" A_LoopField "__eol__" ; this makes it unique otherwise it could be a partial match Section2 .= A_LoopField "`n" } } } If (A_Index > EndLine) Section3 .= A_LoopField "`n" } Output .= Section1 Section2 Section3 Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_InsertLine(Text, StartLine = 1, Endline = 0, InsertText = "") { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% Output .= InsertText "`n" A_LoopField "`n" Else Output .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_ReplaceLine(Text, StartLine = 1, Endline = 0, ReplaceText = "") { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% Output .= ReplaceText "`n" Else Output .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_InsertPrefix(Text, StartLine = 1, EndLine = 0, InsertText = "") { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% OutPut .= InsertText A_LoopField "`n" Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_InsertSuffix(Text, StartLine = 1, EndLine = 0 , InsertText = "") { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% OutPut .= A_LoopField InsertText "`n" Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_TrimLeft(Text, StartLine = 1, EndLine = 0, Count = 1) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { StringTrimLeft, StrOutPut, A_LoopField, %Count% OutPut .= StrOutPut "`n" } Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_TrimRight(Text, StartLine = 1, EndLine = 0, Count = 1) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { StringTrimRight, StrOutPut, A_LoopField, %Count% OutPut .= StrOutPut "`n" } Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_AlignLeft(Text, StartLine = 1, EndLine = 0, Columns = 80, Padding = 0) { Trim:=A_AutoTrim ; store trim settings AutoTrim, On ; make sure AutoTrim is on TF_GetData(OW, Text, FileName) If (Endline = 0 OR Endline = "") EndLine := TF_Count(Text, "`n") + 1 TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { LoopField = %A_LoopField% ; Make use of AutoTrim, should be faster then a RegExReplace. Trims leading and trailing spaces! SpaceNum := Columns-StrLen(LoopField)-1 If (SpaceNum > 0) and (Padding = 1) ; requires padding + keep padding { Left:=TF_SetWidth(LoopField,Columns, 0) ; align left OutPut .= Left "`n" } Else OutPut .= LoopField "`n" } Else OutPut .= A_LoopField "`n" } AutoTrim, %Trim% ; restore original Trim Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_AlignCenter(Text, StartLine = 1, EndLine = 0, Columns = 80, Padding = 0) { Trim:=A_AutoTrim ; store trim settings AutoTrim, On ; make sure AutoTrim is on TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { LoopField = %A_LoopField% ; Make use of AutoTrim, should be faster then a RegExReplace SpaceNum := (Columns-StrLen(LoopField)-1)/2 If (Padding = 1) and (LoopField = "") ; skip empty lines, do not fill with spaces { OutPut .= "`n" Continue } If (StrLen(LoopField) >= Columns) { OutPut .= LoopField "`n" ; add as is Continue } Centered:=TF_SetWidth(LoopField,Columns, 1) ; align center using set width OutPut .= Centered "`n" } Else OutPut .= A_LoopField "`n" } AutoTrim, %Trim% ; restore original Trim Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_AlignRight(Text, StartLine = 1, EndLine = 0, Columns = 80, Skip = 0) { Trim:=A_AutoTrim ; store trim settings AutoTrim, On ; make sure AutoTrim is on TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { LoopField = %A_LoopField% ; Make use of AutoTrim, should be faster then a RegExReplace If (Skip = 1) and (LoopField = "") ; skip empty lines, do not fill with spaces { OutPut .= "`n" Continue } If (StrLen(LoopField) >= Columns) { OutPut .= LoopField "`n" ; add as is Continue } Right:=TF_SetWidth(LoopField,Columns, 2) ; align right using set width OutPut .= Right "`n" } Else OutPut .= A_LoopField "`n" } AutoTrim, %Trim% ; restore original Trim Return TF_ReturnOutPut(OW, OutPut, FileName) } ; Based on: CONCATenate text files, ftp://garbo.uwasa.fi/pc/ts/tsfltc22.zip TF_ConCat(FirstTextFile, SecondTextFile, OutputFile = "", Blanks = 0, FirstPadMargin = 0, SecondPadMargin = 0) { If (Blanks > 0) Loop, %Blanks% InsertBlanks .= A_Space If (FirstPadMargin > 0) Loop, %FirstPadMargin% PaddingFile1 .= A_Space If (SecondPadMargin > 0) Loop, %SecondPadMargin% PaddingFile2 .= A_Space Text:=FirstTextFile TF_GetData(OW, Text, FileName) StringSplit, Str1Lines, Text, `n, `r Text:=SecondTextFile TF_GetData(OW, Text, FileName) StringSplit, Str2Lines, Text, `n, `r Text= ; clear mem ; first we need to determine the file with the most lines for our loop If (Str1Lines0 > Str2Lines0) MaxLoop:=Str1Lines0 Else MaxLoop:=Str2Lines0 Loop, %MaxLoop% { Section1:=Str1Lines%A_Index% Section2:=Str2Lines%A_Index% OutPut .= Section1 PaddingFile1 InsertBlanks Section2 PaddingFile2 "`n" Section1= ; otherwise it will remember the last line from the shortest file or var Section2= } OW=1 ; it is probably 0 so in that case it would create _copy, so set it to 1 If (OutPutFile = "") ; if OutPutFile is empty return as variable OW=2 Return TF_ReturnOutPut(OW, OutPut, OutputFile, 1, 1) } TF_LineNumber(Text, Leading = 0, Restart = 0, Char = 0) ; HT ribbet.1 { global t TF_GetData(OW, Text, FileName) Lines:=TF_Count(Text, "`n") + 1 Padding:=StrLen(Lines) If (Leading = 0) and (Char = 0) Char := A_Space Loop, %Padding% PadLines .= Char Loop, Parse, Text, `n, `r { If Restart = 0 MaxNo = %A_Index% Else { MaxNo++ If MaxNo > %Restart% MaxNo = 1 } LineNumber:= MaxNo If (Leading = 1) { LineNumber := Padlines LineNumber ; add padding StringRight, LineNumber, LineNumber, StrLen(Lines) ; remove excess padding } If (Leading = 0) { LineNumber := LineNumber Padlines ; add padding StringLeft, LineNumber, LineNumber, StrLen(Lines) ; remove excess padding } OutPut .= LineNumber A_Space A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } ; skip = 1, skip shorter lines (e.g. lines shorter startcolumn position) ; modified in TF 3.4, fixed in 3.5 TF_ColGet(Text, StartLine = 1, EndLine = 0, StartColumn = 1, EndColumn = 1, Skip = 0) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList If (StartColumn < 0) { StartColumn++ Loop, Parse, Text, `n, `r ; parsing file/var { If A_Index in %TF_MatchList% { output .= SubStr(A_LoopField,StartColumn) "`n" } else output .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } if RegExMatch(StartColumn, ",|\+|-") { StartColumn:=_MakeMatchList(Text, StartColumn, 1, 1) Loop, Parse, Text, `n, `r ; parsing file/var { If A_Index in %TF_MatchList% { loop, parse, A_LoopField ; parsing LINE char by char { If A_Index in %StartColumn% ; if col in index get char output .= A_LoopField } output .= "`n" } else output .= A_LoopField "`n" } output .= A_LoopField "`n" } else { EndColumn:=(EndColumn+1)-StartColumn Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { StringMid, Section, A_LoopField, StartColumn, EndColumn If (Skip = 1) and (StrLen(A_LoopField) < StartColumn) Continue OutPut .= Section "`n" } } } Return TF_ReturnOutPut(OW, OutPut, FileName) } ; Based on: COLPUT.EXE & CUT.EXE, ftp://garbo.uwasa.fi/pc/ts/tsfltc22.zip ; modified in TF 3.4 TF_ColPut(Text, Startline = 1, EndLine = 0, StartColumn = 1, InsertText = "", Skip = 0) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList If RegExMatch(StartColumn, ",|\+") { StartColumn:=_MakeMatchList(Text, StartColumn, 0, 1) Loop, Parse, Text, `n, `r ; parsing file/var { If A_Index in %TF_MatchList% { loop, parse, A_LoopField ; parsing LINE char by char { If A_Index in %StartColumn% ; if col in index insert text output .= InsertText A_LoopField Else output .= A_LoopField } output .= "`n" } else output .= A_LoopField "`n" } output .= A_LoopField "`n" } else { StartColumn-- Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { If (StartColumn > 0) { StringLeft, Section1, A_LoopField, StartColumn StringMid, Section2, A_LoopField, StartColumn+1 If (Skip = 1) and (StrLen(A_LoopField) < StartColumn) OutPut .= Section1 Section2 "`n" } Else { Section1:=SubStr(A_LoopField, 1, StrLen(A_LoopField) + StartColumn + 1) Section2:=SubStr(A_LoopField, StrLen(A_LoopField) + StartColumn + 2) If (Skip = 1) and (A_LoopField = "") OutPut .= Section1 Section2 "`n" } OutPut .= Section1 InsertText Section2 "`n" } Else OutPut .= A_LoopField "`n" } } Return TF_ReturnOutPut(OW, OutPut, FileName) } ; modified TF 3.4 TF_ColCut(Text, StartLine = 1, EndLine = 0, StartColumn = 1, EndColumn = 1) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList If RegExMatch(StartColumn, ",|\+|-") { StartColumn:=_MakeMatchList(Text, StartColumn, EndColumn, 1) Loop, Parse, Text, `n, `r ; parsing file/var { If A_Index in %TF_MatchList% { loop, parse, A_LoopField ; parsing LINE char by char { If A_Index not in %StartColumn% ; if col not in index get char output .= A_LoopField } output .= "`n" } else output .= A_LoopField "`n" } output .= A_LoopField "`n" } else { StartColumn-- EndColumn++ Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { StringLeft, Section1, A_LoopField, StartColumn StringMid, Section2, A_LoopField, EndColumn OutPut .= Section1 Section2 "`n" } Else OutPut .= A_LoopField "`n" } } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_ReverseLines(Text, StartLine = 1, EndLine = 0) { TF_GetData(OW, Text, FileName) StringSplit, Line, Text, `n, `r ; line0 is number of lines If (EndLine = 0 OR EndLine = "") EndLine:=Line0 If (EndLine > Line0) EndLine:=Line0 CountDown:=EndLine+1 Loop, Parse, Text, `n, `r { If (A_Index < StartLine) Output1 .= A_LoopField "`n" ; section1 If A_Index between %StartLine% and %Endline% { CountDown-- Output2 .= Line%CountDown% "`n" section2 } If (A_Index > EndLine) Output3 .= A_LoopField "`n" } OutPut.= Output1 Output2 Output3 Return TF_ReturnOutPut(OW, OutPut, FileName) } ;TF_SplitFileByLines ;example: ;TF_SplitFileByLines("TestFile.txt", "4", "sfile_", "txt", "1") ; split file every 3 lines ; InFile = 0 skip line e.g. do not include the actual line in any of the output files ; InFile = 1 include line IN current file ; InFile = 2 include line IN next file TF_SplitFileByLines(Text, SplitAt, Prefix = "file", Extension = "txt", InFile = 1) { LineCounter=1 FileCounter=1 Where:=SplitAt Method=1 ; 1 = default, splitat every X lines, ; 2 = splitat: - rotating if applicable ; 3 = splitat: specific lines comma separated TF_GetData(OW, Text, FileName) IfInString, SplitAt, `- ; method 2 { StringSplit, Split, SplitAt, `- Part=1 Where:=Split%Part% Method=2 } IfInString, SplitAt, `, ; method 3 { StringSplit, Split, SplitAt, `, Part=1 Where:=Split%Part% Method=3 } Loop, Parse, Text, `n, `r { OutPut .= A_LoopField "`n" If (LineCounter = Where) { If (InFile = 0) { StringReplace, CheckOutput, PreviousOutput, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutput <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, PreviousOutput, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; skip empty files TF_SetGlobal(Prefix FileCounter,PreviousOutput) Output:= } If (InFile = 1) { StringReplace, CheckOutput, Output, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutput <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, Output, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; skip empty files TF_SetGlobal(Prefix FileCounter,Output) Output:= } If (InFile = 2) { OutPut := PreviousOutput StringReplace, CheckOutput, Output, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutput <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, Output, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; output to array TF_SetGlobal(Prefix FileCounter,Output) OutPut := A_LoopField "`n" } If (Method <> 3) LineCounter=0 ; reset FileCounter++ ; next file Part++ If (Method = 2) ; 2 = splitat: - rotating if applicable { If (Part > Split0) { Part=1 } Where:=Split%Part% } If (Method = 3) ; 3 = splitat: specific lines comma separated { If (Part > Split0) Where:=Split%Split0% Else Where:=Split%Part% } } LineCounter++ PreviousOutput:=Output PreviousLine:=A_LoopField } StringReplace, CheckOutput, Output, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutPut <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, Output, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; output to array { TF_SetGlobal(Prefix FileCounter,Output) TF_SetGlobal(Prefix . "0" , FileCounter) } } ; TF_SplitFileByText("TestFile.txt", "button", "sfile_", "txt") ; split file at every line with button in it, can be regexp ; InFile = 0 skip line e.g. do not include the actual line in any of the output files ; InFile = 1 include line IN current file ; InFile = 2 include line IN next file TF_SplitFileByText(Text, SplitAt, Prefix = "file", Extension = "txt", InFile = 1) { LineCounter=1 FileCounter=1 TF_GetData(OW, Text, FileName) SplitPath, TextFile,, Dir Loop, Parse, Text, `n, `r { OutPut .= A_LoopField "`n" FoundPos:=RegExMatch(A_LoopField, SplitAt) If (FoundPos > 0) { If (InFile = 0) { StringReplace, CheckOutput, PreviousOutput, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutput <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, PreviousOutput, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; output to array TF_SetGlobal(Prefix FileCounter,PreviousOutput) Output:= } If (InFile = 1) { StringReplace, CheckOutput, Output, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutput <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, Output, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; output to array TF_SetGlobal(Prefix FileCounter,Output) Output:= } If (InFile = 2) { OutPut := PreviousOutput StringReplace, CheckOutput, Output, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutput <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, Output, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; output to array TF_SetGlobal(Prefix FileCounter,Output) OutPut := A_LoopField "`n" } LineCounter=0 ; reset FileCounter++ ; next file } LineCounter++ PreviousOutput:=Output PreviousLine:=A_LoopField } StringReplace, CheckOutput, Output, `n, , All StringReplace, CheckOutput, CheckOutput, `r, , All If (CheckOutPut <> "") and (OW <> 2) ; skip empty files TF_ReturnOutPut(1, Output, Prefix FileCounter "." Extension, 0, 1) If (CheckOutput <> "") and (OW = 2) ; output to array { TF_SetGlobal(Prefix FileCounter,Output) TF_SetGlobal(Prefix . "0" , FileCounter) } } TF_Find(Text, StartLine = 1, EndLine = 0, SearchText = "", ReturnFirst = 1, ReturnText = 0) { options:="^[imsxADJUXPS]+\)" if RegExMatch(searchText,options,o) searchText:=RegExReplace(searchText,options,(!InStr(o,"m") ? "m$0(*ANYCRLF)" : "$0")) else searchText:="m)(*ANYCRLF)" searchText options:="^[imsxADJUXPS]+\)" ; Hat tip to sinkfaze, see http://www.autohotkey.com/forum/viewtopic.php?t=60062 if RegExMatch(searchText,options,o) searchText := RegExReplace(searchText,options,(!InStr(o,"m") ? "m$0" : "$0")) else searchText := "m)" . searchText TF_GetData(OW, Text, FileName) If (RegExMatch(Text, SearchText) < 1) Return "0" ; SearchText not in file or error, so do nothing TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { If (RegExMatch(A_LoopField, SearchText) > 0) { If (ReturnText = 0) Lines .= A_Index "," ; line number Else If (ReturnText = 1) Lines .= A_LoopField "`n" ; text of line Else If (ReturnText = 2) Lines .= A_Index ": " A_LoopField "`n" ; add line number If (ReturnFirst = 1) ; only return first occurrence Break } } } If (Lines <> "") StringTrimRight, Lines, Lines, 1 ; trim trailing , or `n Else Lines = 0 ; make sure we return 0 Return Lines } TF_Prepend(File1, File2) { FileList= ( %File1% %File2% ) TF_Merge(FileList,"`n", "!" . File2) Return } TF_Append(File1, File2) { FileList= ( %File2% %File1% ) TF_Merge(FileList,"`n", "!" . File2) Return } ; For TF_Merge You will need to create a Filelist variable, one file per line, ; to pass on to the function: ; FileList= ; ( ; c:\file1.txt ; c:\file2.txt ; ) ; use Loop (files & folders) to create one quickly if you want to merge all TXT files for example ; ; Loop, c:\*.txt ; FileList .= A_LoopFileFullPath "`n" ; ; By default, a new line is used as a separator between two text files ; !merged.txt deletes target file before starting to merge files TF_Merge(FileList, Separator = "`n", FileName = "merged.txt") { OW=0 Loop, Parse, FileList, `n, `r { Append2File= ; Just make sure it is empty IfExist, %A_LoopField% { FileRead, Append2File, %A_LoopField% If not ErrorLevel ; Successfully loaded Output .= Append2File Separator } } If (SubStr(FileName,1,1)="!") ; check if we want to delete the target file before we start { FileName:=SubStr(FileName,2) OW=1 } Return TF_ReturnOutPut(OW, OutPut, FileName, 0, 1) } TF_Wrap(Text, Columns = 80, AllowBreak = 0, StartLine = 1, EndLine = 0) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList If (AllowBreak = 1) Break= Else Break=[ \r?\n] Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { If (StrLen(A_LoopField) > Columns) { LoopField := A_LoopField " " ; just seems to work better by adding a space OutPut .= RegExReplace(LoopField, "(.{1," . Columns . "})" . Break , "$1`n") } Else OutPut .= A_LoopField "`n" } Else OutPut .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } TF_WhiteSpace(Text, RemoveLeading = 1, RemoveTrailing = 1, StartLine = 1, EndLine = 0) { TF_GetData(OW, Text, FileName) TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) ; create MatchList Trim:=A_AutoTrim ; store trim settings AutoTrim, On ; make sure AutoTrim is on Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { If (RemoveLeading = 1) AND (RemoveTrailing = 1) { LoopField = %A_LoopField% Output .= LoopField "`n" Continue } If (RemoveLeading = 1) AND (RemoveTrailing = 0) { LoopField := A_LoopField . "." LoopField = %LoopField% StringTrimRight, LoopField, LoopField, 1 Output .= LoopField "`n" Continue } If (RemoveLeading = 0) AND (RemoveTrailing = 1) { LoopField := "." A_LoopField LoopField = %LoopField% StringTrimLeft, LoopField, LoopField, 1 Output .= LoopField "`n" Continue } If (RemoveLeading = 0) AND (RemoveTrailing = 0) { Output .= A_LoopField "`n" Continue } } Else Output .= A_LoopField "`n" } AutoTrim, %Trim% ; restore original Trim Return TF_ReturnOutPut(OW, OutPut, FileName) } ; Delete lines from file1 in file2 (using StringReplace) ; Partialmatch = 2 added in 3.4 TF_Substract(File1, File2, PartialMatch = 0) { Text:=File1 TF_GetData(OW, Text, FileName) Str1:=Text Text:=File2 TF_GetData(OW, Text, FileName) OutPut:=Text If (OW = 2) File1= ; free mem in case of var/text OutPut .= "`n" ; just to make sure the StringReplace will work If (PartialMatch = 2) { Loop, Parse, Str1, `n, `r { IfInString, Output, %A_LoopField% { Output:= RegExReplace(Output, "im)^.*" . A_LoopField . ".*\r?\n?", replace) } } } Else If (PartialMatch = 1) ; allow paRTIal match { Loop, Parse, Str1, `n, `r StringReplace, Output, Output, %A_LoopField%, , All ; remove lines from file1 in file2 } Else If (PartialMatch = 0) { search:="m)^(.*)$" replace=__bol__$1__eol__ Output:=RegExReplace(Output, search, replace) StringReplace, Output, Output, `n__eol__,__eol__ , All ; strange fix but seems to be needed. Loop, Parse, Str1, `n, `r StringReplace, Output, Output, __bol__%A_LoopField%__eol__, , All ; remove lines from file1 in file2 } If (PartialMatch = 0) { StringReplace, Output, Output, __bol__, , All StringReplace, Output, Output, __eol__, , All } ; Remove all blank lines from the text in a variable: Loop { StringReplace, Output, Output, `r`n`r`n, `r`n, UseErrorLevel if (ErrorLevel = 0) or (ErrorLevel = 1) ; No more replacements needed. break } Return TF_ReturnOutPut(OW, OutPut, FileName, 0) } ; Similar to "BK Replace EM" RangeReplace TF_RangeReplace(Text, SearchTextBegin, SearchTextEnd, ReplaceText = "", CaseSensitive = "False", KeepBegin = 0, KeepEnd = 0) { TF_GetData(OW, Text, FileName) IfNotInString, Text, %SearchText% Return Text ; SearchTextBegin not in TextFile so return and do nothing, we have to return Text in case of a variable otherwise it would empty the variable contents bug fix 3.3 Start = 0 End = 0 If (KeepBegin = 1) KeepBegin:=SearchTextBegin Else KeepBegin= If (KeepEnd = 1) KeepEnd:= SearchTextEnd Else KeepEnd= If (SearchTextBegin = "") Start=1 If (SearchTextEnd = "") End=2 Loop, Parse, Text, `n, `r { If (End = 1) ; end has been found already, replacement made simply continue to add all lines { Output .= A_LoopField "`n" Continue } If (Start = 0) ; start hasn't been found { If (InStr(A_LoopField,SearchTextBegin,CaseSensitive)) ; start has been found { Start = 1 KeepSection := SubStr(A_LoopField, 1, InStr(A_LoopField, SearchTextBegin)-1) EndSection := SubStr(A_LoopField, InStr(A_LoopField, SearchTextBegin)-1) ; check if SearchEndText is in second part of line If (InStr(EndSection,SearchTextEnd,CaseSensitive)) ; end found { EndSection := ReplaceText KeepEnd SubStr(EndSection, InStr(EndSection, SearchTextEnd) + StrLen(SearchTextEnd) ) "`n" If (End <> 2) End=1 If (End = 2) EndSection= } Else EndSection= Output .= KeepSection KeepBegin EndSection Continue } Else Output .= A_LoopField "`n" ; if not found yet simply add } If (Start = 1) and (End <> 2) ; start has been found, now look for end if end isn't an empty string { If (InStr(A_LoopField,SearchTextEnd,CaseSensitive)) ; end found { End = 1 Output .= ReplaceText KeepEnd SubStr(A_LoopField, InStr(A_LoopField, SearchTextEnd) + StrLen(SearchTextEnd) ) "`n" } } } If (End = 2) Output .= ReplaceText Return TF_ReturnOutPut(OW, OutPut, FileName) } ; Create file of X lines and Y columns, fill with space or other character(s) TF_MakeFile(Text, Lines = 1, Columns = 1, Fill = " ") { OW=1 If (Text = "") ; if OutPutFile is empty return as variable OW=2 Loop, % Columns Cols .= Fill Loop, % Lines Output .= Cols "`n" Return TF_ReturnOutPut(OW, OutPut, Text, 1, 1) } ; Convert tabs to spaces, shorthand for TF_ReplaceInLines TF_Tab2Spaces(Text, TabStop = 4, StartLine = 1, EndLine =0) { Loop, % TabStop Replace .= A_Space Return TF_ReplaceInLines(Text, StartLine, EndLine, A_Tab, Replace) } ; Convert spaces to tabs, shorthand for TF_ReplaceInLines TF_Spaces2Tab(Text, TabStop = 4, StartLine = 1, EndLine =0) { Loop, % TabStop Replace .= A_Space Return TF_ReplaceInLines(Text, StartLine, EndLine, Replace, A_Tab) } ; Sort (section of) a text file TF_Sort(Text, SortOptions = "", StartLine = 1, EndLine = 0) ; use the SORT options http://www.autohotkey.com/docs/commands/Sort.htm { TF_GetData(OW, Text, FileName) If StartLine contains -,+,`, ; no sections, incremental or multiple line input Return If (StartLine = 1) and (Endline = 0) ; process entire file { Output:=Text Sort, Output, %SortOptions% } Else { Output := TF_ReadLines(Text, 1, StartLine-1) ; get first section ToSort := TF_ReadLines(Text, StartLine, EndLine) ; get section to sort Sort, ToSort, %SortOptions% OutPut .= ToSort OutPut .= TF_ReadLines(Text, EndLine+1) ; append last section } Return TF_ReturnOutPut(OW, OutPut, FileName, 0) ; https://github.com/hi5/TF/issues/11 } TF_Tail(Text, Lines = 1, RemoveTrailing = 0, ReturnEmpty = 1) { TF_GetData(OW, Text, FileName) Neg = 0 If (Lines < 0) { Neg=1 Lines:= Lines * -1 } If (ReturnEmpty = 0) ; remove blank lines first so we can't return any blank lines anyway { Loop, Parse, Text, `n, `r OutPut .= (RegExMatch(A_LoopField,"[\S]+?\r?\n?")) ? A_LoopField "`n" : StringTrimRight, OutPut, OutPut, 1 ; remove trailing `n added by loop above Text:=OutPut OutPut= } If (Neg = 1) ; get only one line! { Lines++ Output:=Text StringGetPos, Pos, Output, `n, R%Lines% ; These next two Lines by Tuncay see StringTrimLeft, Output, Output, % ++Pos ; http://www.autoHotkey.com/forum/viewtopic.php?p=262375#262375 StringGetPos, Pos, Output, `n StringLeft, Output, Output, % Pos Output .= "`n" } Else { Output:=Text StringGetPos, Pos, Output, `n, R%Lines% ; These next two Lines by Tuncay see StringTrimLeft, Output, Output, % ++Pos ; http://www.autoHotkey.com/forum/viewtopic.php?p=262375#262375 Output .= "`n" } OW = 2 ; make sure we return variable not process file Return TF_ReturnOutPut(OW, OutPut, FileName, RemoveTrailing) } TF_Count(String, Char) { StringReplace, String, String, %Char%,, UseErrorLevel Return ErrorLevel } TF_Save(Text, FileName, OverWrite = 1) { ; HugoV write file Return TF_ReturnOutPut(OverWrite, Text, FileName, 0, 1) } TF(TextFile, CreateGlobalVar = "T") { ; read contents of file in output and %output% as global var ... http://www.autohotkey.com/forum/viewtopic.php?p=313120#313120 global FileRead, %CreateGlobalVar%, %TextFile% Return, (%CreateGlobalVar%) } ; TF_Join ; SmartJoin: Detect if CHAR(s) is/are already present at the end of the line before joining the next, this to prevent unnecessary double spaces for example. ; Char: character(s) to use between new lines, defaults to a space. To use nothing use "" TF_Join(Text, StartLine = 1, EndLine = 0, SmartJoin = 0, Char = 0) { If ( (InStr(StartLine,",") > 0) AND (InStr(StartLine,"-") = 0) ) OR (InStr(StartLine,"+") > 0) Return Text ; can't do multiplelines, only multiple sections of lines e.g. "1,5" bad "1-5,15-10" good, "2+2" also bad TF_GetData(OW, Text, FileName) If (InStr(Text,"`n") = 0) Return Text ; there are no lines to join so just return Text If (InStr(StartLine,"-") > 0) ; OK, we need some counter-intuitive string mashing to substract ONE from the "endline" parameter { Loop, Parse, StartLine, CSV { StringSplit, part, A_LoopField, - NewStartLine .= part1 "-" (part2-1) "," } StringTrimRight, StartLine, NewStartLine, 1 } If (Endline > 0) Endline-- TF_MatchList:=_MakeMatchList(Text, StartLine, EndLine, 0, A_ThisFunc) If (Char = 0) Char:=A_Space Char_Org:=Char GetRightLen:=StrLen(Char)-1 Loop, Parse, Text, `n, `r { If A_Index in %TF_MatchList% { If (SmartJoin = 1) { GetRightText:=SubStr(A_LoopField,0) If (GetRightText = Char) Char= } Output .= A_LoopField Char Char:=Char_Org } Else Output .= A_LoopField "`n" } Return TF_ReturnOutPut(OW, OutPut, FileName) } ;----- Helper functions ---------------- TF_SetGlobal(var, content = "") ; helper function for TF_Split* to return array and not files, credits Tuncay :-) { global %var% := content } ; Helper function to determine if VAR/TEXT or FILE is passed to TF ; Update 11 January 2010 (skip filecheck if `n in Text -> can't be file) TF_GetData(byref OW, byref Text, byref FileName) { If (text = 0 "") ; v3.6 -> v3.7 https://github.com/hi5/TF/issues/4 and https://autohotkey.com/boards/viewtopic.php?p=142166#p142166 in case user passes on zero/zeros ("0000") as text - will error out when passing on one 0 and there is no file with that name { IfNotExist, %Text% ; additional check to see if a file 0 exists { MsgBox, 48, TF Lib Error, % "Read Error - possible reasons (see documentation):`n- Perhaps you used !""file.txt"" vs ""!file.txt""`n- A single zero (0) was passed on to a TF function as text" ExitApp } } OW=0 ; default setting: asume it is a file and create file_copy IfNotInString, Text, `n ; it can be a file as the Text doesn't contact a newline character { If (SubStr(Text,1,1)="!") ; first we check for "overwrite" { Text:=SubStr(Text,2) OW=1 ; overwrite file (if it is a file) } IfNotExist, %Text% ; now we can check if the file exists, it doesn't so it is a var { If (OW=1) ; the variable started with a ! so we need to put it back because it is variable/text not a file Text:= "!" . Text OW=2 ; no file, so it is a var or Text passed on directly to TF } } Else ; there is a newline character in Text so it has to be a variable { OW=2 } If (OW = 0) or (OW = 1) ; it is a file, so we have to read into var Text { Text := (SubStr(Text,1,1)="!") ? (SubStr(Text,2)) : Text FileName=%Text% ; Store FileName FileRead, Text, %Text% ; Read file and return as var Text If (ErrorLevel > 0) { MsgBox, 48, TF Lib Error, % "Can not read " FileName ExitApp } } Return } ; Skan - http://www.autohotkey.com/forum/viewtopic.php?p=45880#45880 ; SetWidth() : SetWidth increases a String's length by adding spaces to it and aligns it Left/Center/Right. ( Requires Space() ) TF_SetWidth(Text,Width,AlignText) { If (AlignText!=0 and AlignText!=1 and AlignText!=2) AlignText=0 If AlignText=0 { RetStr= % (Text)TF_Space(Width) StringLeft, RetText, RetText, %Width% } If AlignText=1 { Spaces:=(Width-(StrLen(Text))) RetStr= % TF_Space(Round(Spaces/2))(Text)TF_Space(Spaces-(Round(Spaces/2))) } If AlignText=2 { RetStr= % TF_Space(Width)(Text) StringRight, RetStr, RetStr, %Width% } Return RetStr } ; Skan - http://www.autohotkey.com/forum/viewtopic.php?p=45880#45880 TF_Space(Width) { Loop,%Width% Space=% Space Chr(32) Return Space } ; Write to file or return variable depending on input TF_ReturnOutPut(OW, Text, FileName, TrimTrailing = 1, CreateNewFile = 0) { If (OW = 0) ; input was file, file_copy will be created, if it already exist file_copy will be overwritten { IfNotExist, % FileName ; check if file Exist, if not return otherwise it would create an empty file. Thanks for the idea Murp|e { If (CreateNewFile = 1) ; CreateNewFile used for TF_SplitFileBy* and others { OW = 1 Goto CreateNewFile } Else Return } If (TrimTrailing = 1) StringTrimRight, Text, Text, 1 ; remove trailing `n SplitPath, FileName,, Dir, Ext, Name If (Dir = "") ; if Dir is empty Text & script are in same directory Dir := A_WorkingDir 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, %Text%, % Dir "\" Name "_copy." Ext Return Errorlevel ? False : True } CreateNewFile: If (OW = 1) ; input was file, will be overwritten by output { IfNotExist, % FileName ; 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* and others Return } If (TrimTrailing = 1) StringTrimRight, Text, Text, 1 ; remove trailing `n SplitPath, FileName,, Dir, Ext, Name If (Dir = "") ; if Dir is empty Text & script are in same directory Dir := A_WorkingDir 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, %Text%, % Dir "\" Name "." Ext Return Errorlevel ? False : True } If (OW = 2) ; input was var, return variable { If (TrimTrailing = 1) StringTrimRight, Text, Text, 1 ; remove trailing `n Return Text } } ; _MakeMatchList() ; Purpose: ; Make a MatchList which is used in various functions ; Using a MatchList gives greater flexibility so you can process multiple ; sections of lines in one go avoiding repetitive fileread/append actions ; For TF 3.4 added COL = 0/1 option (for TF_Col* functions) and CallFunc for ; all TF_* functions to facilitate bug tracking _MakeMatchList(Text, Start = 1, End = 0, Col = 0, CallFunc = "Not available") { ErrorList= (join| Error 01: Invalid StartLine parameter (non numerical character)`nFunction used: %CallFunc% Error 02: Invalid EndLine parameter (non numerical character)`nFunction used: %CallFunc% Error 03: Invalid StartLine parameter (only one + allowed)`nFunction used: %CallFunc% ) StringSplit, ErrorMessage, ErrorList, | Error = 0 If (Col = 1) { LongestLine:=TF_Stat(Text) If (End > LongestLine) or (End = 1) ; FIXITHERE BUG End:=LongestLine } TF_MatchList= ; just to be sure If (Start = 0 or Start = "") Start = 1 ; some basic error checking ; error: only digits - and + allowed If (RegExReplace(Start, "[ 0-9+\-\,]", "") <> "") Error = 1 If (RegExReplace(End, "[0-9 ]", "") <> "") Error = 2 ; error: only one + allowed If (TF_Count(Start,"+") > 1) Error = 3 If (Error > 0 ) { MsgBox, 48, TF Lib Error, % ErrorMessage%Error% ExitApp } ; Option #0 [ added 30-Oct-2010 ] ; Startline has negative value so process X last lines of file ; endline parameter ignored If (Start < 0) ; remove last X lines from file, endline parameter ignored { Start:=TF_CountLines(Text) + Start + 1 End=0 ; now continue } ; Option #1 ; StartLine has + character indicating startline + incremental processing. ; EndLine will be used ; Make TF_MatchList IfInString, Start, `+ { If (End = 0 or End = "") ; determine number of lines End:= TF_Count(Text, "`n") + 1 StringSplit, Section, Start, `, ; we need to create a new "TF_MatchList" so we split by , Loop, %Section0% { StringSplit, SectionLines, Section%A_Index%, `+ LoopSection:=End + 1 - SectionLines1 Counter=0 TF_MatchList .= SectionLines1 "," Loop, %LoopSection% { If (A_Index >= End) ; Break If (Counter = (SectionLines2-1)) ; counter is smaller than the incremental value so skip { TF_MatchList .= (SectionLines1 + A_Index) "," Counter=0 } Else Counter++ } } StringTrimRight, TF_MatchList, TF_MatchList, 1 ; remove trailing , Return TF_MatchList } ; Option #2 ; StartLine has - character indicating from-to, COULD be multiple sections. ; EndLine will be ignored ; Make TF_MatchList IfInString, Start, `- { StringSplit, Section, Start, `, ; we need to create a new "TF_MatchList" so we split by , Loop, %Section0% { StringSplit, SectionLines, Section%A_Index%, `- LoopSection:=SectionLines2 + 1 - SectionLines1 Loop, %LoopSection% { TF_MatchList .= (SectionLines1 - 1 + A_Index) "," } } StringTrimRight, TF_MatchList, TF_MatchList, 1 ; remove trailing , Return TF_MatchList } ; Option #3 ; StartLine has comma indicating multiple lines. ; EndLine will be ignored IfInString, Start, `, { TF_MatchList:=Start Return TF_MatchList } ; Option #4 ; parameters passed on as StartLine, EndLine. ; Make TF_MatchList from StartLine to EndLine If (End = 0 or End = "") ; determine number of lines End:= TF_Count(Text, "`n") + 1 LoopTimes:=End-Start Loop, %LoopTimes% { TF_MatchList .= (Start - 1 + A_Index) "," } TF_MatchList .= End "," StringTrimRight, TF_MatchList, TF_MatchList, 1 ; remove trailing , Return TF_MatchList } ; added for TF 3.4 col functions - currently only gets longest line may change in future TF_Stat(Text) { TF_GetData(OW, Text, FileName) Sort, Text, f _AscendingLinesL Pos:=InStr(Text,"`n")-1 Return pos } _AscendingLinesL(a1, a2) ; used by TF_Stat { Return StrLen(a2) - StrLen(a1) } /* -------------- */