Page 1 of 1

Edit text within an .ini file

Posted: 18 Oct 2019, 16:00
by Lem2001
How would I go about editing and ini file to partially remove some of its contents (between two section headers)?

For example, if I had a file called settings.ini and within this file was sections (each one enclosed in square brackets) something like this:

Code: Select all

[Preferences]
color=#ff00ee
size=34
etc.
[Recent]
seiejdieef
runjowoeud
rrudisjsuw
[Bookmarks]
What AHK commands would I use to delete whatever text is between 'Recent' and 'Bookmarks' sections (not matter how many lines) and leave just 3 blank lines between the two section headers, and then save the file?

I've never used AHK to do anything within a file itself before, so I want to make sure that I get it right and not accidentally delete other important settings in the .ini file.

Thanks

Re: Edit text within an .ini file

Posted: 19 Oct 2019, 02:01
by AHKStudent
AHK has commands to work with ini files but the way ini files work there are no blank lines when you remove a key. You can read about the main ini commands (read, write and delete) in the documentation https://www.autohotkey.com/docs/commands/IniRead.htm

Here is some code that can do what you want, maybe someone can post a better way. Always backup the files I did not test the code well.

Code: Select all

FileName := "inidata.ini"
FileRead, t, % FileName
cInd = 99999 ; very bad practice 
cIndend = 99999 ; very bad practice 
Loop, Parse, t, `n
{
	If InStr(A_LoopField, "[Recent]")
		cInd := A_Index 
	If InStr(A_LoopField, "[Bookmarks]")
		cIndend := A_Index
	If ((A_Index > cInd) && (A_Index < cIndend)) {
		NF .= "`n"
	}
	Else {
		NF .= A_LoopField "`n"
	}
}
MsgBox, % NF

Re: Edit text within an .ini file

Posted: 19 Oct 2019, 06:19
by Odlanir
Two ways, I think the first is the most reliable.

Code: Select all

FileDelete, TestINI_New.ini
FileRead, AllFile, TestINI.ini
FileAppend, % RegExReplace(AllFile, "`amsU)(?<=\[Recent\])(.*)(?=\[)","`n`n`n$2"), TestINI_New.ini
run, TestINI_New.ini
;~ FileMove,TestINI_New.ini, TestINI.ini, 1 ; <----- Replace your original ini file
ExitApp

Code: Select all

IniRead, AllSection ,TestINI.ini, Recent
allRecentKeys := Object(StrSplit(RegExReplace(AllSection ",1","`n",",1,"),",")*), Count := 0
FileDelete, TestINI_New.ini
Loop, read, TestINI.ini, TestINI_New.ini
{   
   If !(allRecentKeys.Haskey(A_LoopReadLine))
      FileAppend, %A_LoopReadLine%`n
   else if ( ++Count <= 3) { ; write max 3 blank lines in Recent section
      FileAppend, % " `n"
   }
}
run, TestINI_New.ini
;~ FileMove,TestINI_New.ini, TestINI.ini, 1 ; <----- Replace your original ini file

Re: Edit text within an .ini file

Posted: 20 Oct 2019, 10:27
by Lem2001
Thank you both for your replies.

Odlanir, your first example was the one I ended up using. It is very clean and elegant (and works well). I could not have figured this out for myself (Regex is not my strong point).

There is just one problem with it; the method that you've used for detecting the next header section is simply the next appearance of a square bracket.

This means that any 'recent data' that includes square brackets causes the script to stop short of deleting anything after that.

Question:

Is it possible to amend the Regex to detect the next instance of a line that starts and ends with square brackets (i.e. no characters or spaces before or after the square brackets on that line). This would seem to be a more reliable detection method, without having to hard-code the actual ini section name (which would cause havoc if the sections ever changed order).

Thanks

Re: Edit text within an .ini file  Topic is solved

Posted: 20 Oct 2019, 11:56
by Odlanir
This should work:

Code: Select all

FileDelete, TestINI_New.ini
FileRead, AllFile, TestINI.ini
FileAppend, % RegExReplace(AllFile, "`amsU)(?<=\[Recent\])(.*)(?=^\[\w+]$)","`n`n`n$2"), TestINI_New.ini
run, TestINI_New.ini
Tested with this sample ini:
[Preferences]
color=#ff00ee
size=34
etc.
[Bookmarks]
kk=10
ss=20
jj=30
[Recent]
sei[braketopen
runjowoeud
[]
aaa[inside]dadad
[test1]ouoieuoeiue
dklò[kòl
iuos[test2]
[Another]
qq=10
bb=212341531
cc=45
[LastSection]
jj=123

Re: Edit text within an .ini file

Posted: 20 Oct 2019, 12:17
by AHKStudent
Odlanir wrote:
20 Oct 2019, 11:56
This should work:

Code: Select all

FileDelete, TestINI_New.ini
FileRead, AllFile, TestINI.ini
FileAppend, % RegExReplace(AllFile, "`amsU)(?<=\[Recent\])(.*)(?=^\[\w+]$)","`n`n`n$2"), TestINI_New.ini
run, TestINI_New.ini
Tested with this sample ini:
[Preferences]
color=#ff00ee
size=34
etc.
[Bookmarks]
kk=10
ss=20
jj=30
[Recent]
sei[braketopen
runjowoeud
[]
aaa[inside]dadad
[test1]ouoieuoeiue
dklò[kòl
iuos[test2]
[Another]
qq=10
bb=212341531
cc=45
[LastSection]
jj=123
That is amazing :thumbup: , it motivates me to learn regex, sorry OP for my long code

Re: Edit text within an .ini file

Posted: 21 Oct 2019, 23:36
by Lem2001
AHKStudent wrote:
20 Oct 2019, 12:17
sorry OP for my long code
Not at all.

I am grateful to you for taking the time to reply to try to help me.

Re: Edit text within an .ini file

Posted: 21 Oct 2019, 23:37
by Lem2001
Odlanir wrote:
20 Oct 2019, 11:56
This should work:
This is amazing!

It covers every possible instance while keeping the next section heading (and the rest of the ini content) safe.

Thank you so much for your help.

Re: Edit text within an .ini file

Posted: 22 Oct 2019, 02:24
by teadrinker
Odlanir wrote:

Code: Select all

RegExReplace(AllFile, "`amsU)(?<=\[Recent\])(.*)(?=^\[\w+]$)","`n`n`n$2")
It seems that only two blank lines is here. 3 blank lines require 4 line breaks. $2 does nothing, it's redundant.

Re: Edit text within an .ini file

Posted: 22 Oct 2019, 02:56
by Odlanir
@teadrinker You're right! Thanks.

Re: Edit text within an .ini file

Posted: 22 Oct 2019, 09:08
by Lem2001
teadrinker wrote:
22 Oct 2019, 02:24
3 blank lines require 4 line breaks.
Yeah, that was the only part of the Regex command that I understood, so I had already fixed that bit by just adding another line break.


teadrinker wrote:
22 Oct 2019, 02:24
$2 does nothing, it's redundant.
I didn't know what $2 did, so I just left it alone. But now that I know it's not needed, I have gone ahead and removed it.

Thanks.

Re: Edit text within an .ini file

Posted: 22 Oct 2019, 16:12
by Lem2001
I can't believe that I am back asking for help on this topic again <sigh>. Sorry.

Everything was working great, but I have discovered that after cleaning, when I next run the software (and more recent entries get created) the [Recent] section has moved to the very end of the .ini file! Presumably it did this because there were no longer any recent entries to keep the [Recent] heading where it was originally located, so the original got wiped and the new [Recent] appended at the end of the ini file instead.

This means that there is not always a subsequent section heading after [Recent], and in that instance the recent entries don't get deleted.

The existing Regex works perfectly when [Recent] is not the last heading in the ini file. Is it possible to incorporate detecting the end of a file too? so that if there is no section heading after [Recent] before the end of the file, that it deletes the contents after Recent to the end of the file (except for leaving 3 blank lines as previously).

Such a command does makes me a little nervous (because I wouldn't want it to accidentally wipe the entire file under certain circumstances) therefore I don't want to attempt messing about with the Regex myself to try to achieve this.

Re: Edit text within an .ini file

Posted: 22 Oct 2019, 18:06
by teadrinker
Something like this:

Code: Select all

RegExReplace(AllFile, "s)(^|\R)\[Recent](?=(\R|$))\K(.*?(?=\R\[\w+](?2))|(.(?!.*\R\[\w+](?2))+)*$)", "`n`n`n")

Re: Edit text within an .ini file

Posted: 27 Oct 2019, 12:45
by Lem2001
teadrinker wrote:
22 Oct 2019, 18:06
Something like this:

Code: Select all

RegExReplace(AllFile, "s)(^|\R)\[Recent](?=(\R|$))\K(.*?(?=\R\[\w+](?2))|(.(?!.*\R\[\w+](?2))+)*$)", "`n`n`n")
Thank you very much. This works great!

I was ready to closely examine the changes made to the Regex command (compared to the previous solution) to see if I could start to get a basic understanding of the piece of the Regex that was added to give the ability to remove 'Recent' entries even when the [Recent] section header was located at the end of the ini file.

However, the changes are so significant compared to the original that I haven't got a clue what the hell is going on :lol:
I'm just grateful that it works.

Thanks again, teadrinker and Odlanir.