Swap/move lines in text file

Get help with using AutoHotkey and its commands and hotkeys
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Swap/move lines in text file

22 Jan 2014, 03:52

Hi there, I'm relatively new to scripting so I would love some help on how to swap two lines in a text file (or move a particular line up or down one line if that works differently). They wouldn't have a consistent line number but a search string particular to each.

So this:
apple
apple
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape

becomes this:
apple
apple
grape
rhubarb
grape
rhubarb
banana
apple
grape
rhubarb

The rhubarb and grape lines have been swapped (or grape has moved up, or rhubarb has moved down). Cheers :-)
User avatar
dmg
Posts: 282
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Swap/move lines in text file

22 Jan 2014, 04:05

That should be doable. So, is the ideal goal to be able to feed it a list and a search string and when it finds that string to move it up one line? Or are you really wanting to swap two strings in the list regardless of their relative positions?
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
Sjc1000
Posts: 39
Joined: 02 Oct 2013, 02:07

Re: Swap/move lines in text file

22 Jan 2014, 04:59

Hi kiwichick, Welcome to the Ahkscript forum.


fileSwapLines( fileDirectory, line1, line2 )

This function will swap line 1 with line 2 of the file at fileDirectory.

Code: Select all

fileSwapLines("D:\HTML\css test\style.css", 1, 2 )


fileSwapLines( fileDir, line1, line2 )
{	fileRead, data, % fileDir
	FileDelete, % fileDir
	
	fileArray	:= {}
		
	Loop, Parse, data, `n
		fileArray.insert( A_LoopField )


	swap				:= fileArray[ line1 ]
	fileArray[ line1 ]	:= fileArray[ line2 ]	
	fileArray[ line2 ]	:= swap			
	

	for key, val in fileArray
		out 		.= val "`n"

	FileAppend, % out, % fileDir
	Return 1
}
Please find me on the IRC if you have any questions, I'm never on the forum anymore.
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Swap/move lines in text file

22 Jan 2014, 14:59

perfect! tested and it swapped as stipulated! :ugeek:

apple1
apple2
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape
Last edited by Guest10 on 22 Jan 2014, 23:09, edited 1 time in total.
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

22 Jan 2014, 21:07

Sjc1000 wrote:Hi kiwichick, Welcome to the Ahkscript forum.
Thank you very much :-)

Your code works great but, as you said it swaps the first and second lines, which isn't what I'm after. The lines I want to swap could be any number (they will be consecutive numbers but not consistent numbers) and there will be multiple instances to change.
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

22 Jan 2014, 21:08

dmg wrote:So, is the ideal goal to be able to feed it a list and a search string and when it finds that string to move it up one line?
Yes exactly!
dmg wrote:Or are you really wanting to swap two strings in the list regardless of their relative positions?
No.

The two lines will always be consecutive, regardless of where they are in the list, so it doesn't matter if one goes up or one goes down as long as the end result is they swap. But there will always be multiple instances of them (as per the example) so all of them must be changed.
User avatar
dmg
Posts: 282
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Swap/move lines in text file

22 Jan 2014, 21:35

OK! Now that I know what you are after I will see what I can do. It may take a day or two so your patience is appreciated. :D
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
User avatar
dmg
Posts: 282
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Swap/move lines in text file

22 Jan 2014, 22:24

Well, so much for it taking a day or two!:

Code: Select all

list := 
(
"apple
apple
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape"
)
msgbox, % list
msgbox, % _upshift(list, "grape")

_upshift(list, line)
 {
   items := {}
   loop, parse, list, `n
    {
      items.insert(a_loopfield)
    }
   loop, % items.maxindex()
    {
      if (items[a_index] = line)
        {
          items.remove(a_index)
          items.insert(a_index - 1, line)
        }
    }
   loop, % items.maxindex()
    {
      out .= items[a_index] . "`n"
    }
   return rtrim(out, "`n")
 }
I think this does what you asked for. I implemented it as a function so you should be able to plug the code in with minimal trouble. Supply the function call with the list of words and the word you want to move up one line when found.

I chose to move the word grape up in the list because it avoided an issue with sorting. Moving rhubarb down caused errors because the code would move rhubarb one space ahead, but then it found it again and moved it again.

If it has any trouble or you need help understanding it just post back. :)
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Swap/move lines in text file

22 Jan 2014, 23:23

i am not sure what the objective for this implementation is but seems to work albeit very confusing. :? could you re-explain what this script is doing? :ugeek:
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

23 Jan 2014, 00:09

Guest10 wrote:i am not sure what the objective for this implementation is but seems to work albeit very confusing. :? could you re-explain what this script is doing? :ugeek:
As I said in my original post, it's just for swapping the order of two sets of lines in a text file. The fruit names in the example are not the literal strings I'm working with. They are strings of code I have exported from one program to use in another but I need to swap the order of particular commands in order to make them work properly in the new program. It would be an ongoing requirement so much easier to do with a script than by hand :-)
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

23 Jan 2014, 00:13

dmg wrote:If it has any trouble or you need help understanding it just post back. :)
Thank you so much, it works great!!! Now I just need to try and modify it for my needs. I'm not very experienced at scripting so it may take me a while. I definitely anticipate returning for more help :-)
User avatar
dmg
Posts: 282
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Swap/move lines in text file

23 Jan 2014, 00:34

Glad it looks like it will work for you! Post back anytime. I will check this thread every now and then, or you can PM me either here or on the other forum:
http://www.autohotkey.com/board/
My user name is dmg on both. :)
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

23 Jan 2014, 02:04

dmg wrote:you can PM me either here or on the other forum:
http://www.autohotkey.com/board/
My user name is dmg on both. :)
Yes I posted there as well but I haven't had a reply to my recent update to the post so I tried here.

The only problem I immediately have (and I totally knew I'd have trouble with this) is that the list (file contents) isn't static. It will change probably with each use. So I'm guessing I would read the file into a variable and use that. So this:

list :=
(
"apple
apple
...
rhubarb
grape"
)

would become this:

readfile, filecontentsvar, %filetoread%

list :=
(
"filecontentsvar"
)

Am I even in the right ballpark and, if so, how do I make it work because I'm obviously not doing it right? I don't know whether I enclose the variable in %, leave out the "" or what :-)
User avatar
Blackholyman
Posts: 1283
Joined: 29 Sep 2013, 22:57
Facebook: socialjsz
Google: +Jszapp
Location: Denmark
Contact:

Re: Swap/move lines in text file

23 Jan 2014, 02:22

Code: Select all

readfile, filecontentsvar, %filetoread%

list := filecontentsvar
or just replace list with filecontentsvar where needed
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

23 Jan 2014, 02:53

Blackholyman wrote:

Code: Select all

readfile, filecontentsvar, %filetoread%

list := filecontentsvar
or just replace list with filecontentsvar where needed
Thanks Blackholyman but it didn't work. Just in case you didn't see it, it needs to work with the code that dmg posted above.
User avatar
dmg
Posts: 282
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Swap/move lines in text file

23 Jan 2014, 05:05

You have the basic idea, you just need to understand the syntax. Your code is what we might call pseudo code. It illustrates an idea but is far from being functional. It can be very useful when trying to explain an idea to another scripter.

The command you want is FileRead:
http://auto-hotkey.com/docs/commands/FileRead.htm

It reads the entire contents of a plain text file into a variable to be operated on. I say plain text file simply to mean any fine that contains characters with no formatting info included. (I apologize if I explain something you already know. I have no way of knowing what you understand or don't, so please do not think me condescending)

The portion of my code that contains the list:

Code: Select all

list :=
(
"apple
apple
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape"
)
Is just assigning static text to the list variable. The () are what is called a continuation section, meaning it allows the content on multiple lines to be added to the variable with line breaks in tact. Since you will be using a command to get the var content you don't need that part of the code at all.

Here is my code with the FileRead command added:

Code: Select all

fileread, list, filename

msgbox, % _upshift(list, "grape")

_upshift(list, line)
 {
   items := {}
   loop, parse, list, `n
    {
      items.insert(a_loopfield)
    }
   loop, % items.maxindex()
    {
      if (items[a_index] = line)
       {
         items.remove(a_index)
         items.insert(a_index - 1, line)
       }
    }
   loop, % items.maxindex()
    {
      out .= items[a_index] . "`n"
    }
   return rtrim(out, "`n")
 }
If you replace the filename parameter with the path to your file, and set the line you want moved, it should work. But even this will only display the changed content in a msgbox. You will probably want to output the changed content to another file, right?
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact
kiwichick
Posts: 94
Joined: 21 Jan 2014, 22:03

Re: Swap/move lines in text file

23 Jan 2014, 17:53

dmg wrote:You have the basic idea, you just need to understand the syntax. Your code is what we might call pseudo code. It illustrates an idea but is far from being functional. It can be very useful when trying to explain an idea to another scripter.

The command you want is FileRead:
http://auto-hotkey.com/docs/commands/FileRead.htm

It reads the entire contents of a plain text file into a variable to be operated on. I say plain text file simply to mean any fine that contains characters with no formatting info included. (I apologize if I explain something you already know. I have no way of knowing what you understand or don't, so please do not think me condescending)

If you replace the filename parameter with the path to your file, and set the line you want moved, it should work. But even this will only display the changed content in a msgbox. You will probably want to output the changed content to another file, right?
Yip I actually do understand all of that :-) I certainly do not think you're being condescending :-) And I can see how the code is meant to work but it doesn't. I'm sure it must be something simple I'm doing (like quote marks missing or put around the wrong thing) but I don't know enough to be able to troubleshoot.

If I use the original code you gave me and type my file contents into the list := (.....) section and change _upshift(list, "grape") to what I want to "shift" (multi-word line), it works fine. I can then also assign the shift to a variable and that works fine too. This works:

Code: Select all

$shift = Gui, 2:Font

list :=
(
"Gui, 2:Add,Text, x272 y24 w227 h193, %$output_sign% 
Gui, 2:Add,Picture, x264 y152 w113 h89, %$image_symbol% 
Gui, 2:Add,Text, x48 y56 w141 h137, %$output_element% 
Gui, 2:Font 
Gui, 2:Add,Picture, x680 y32 w201 h193, %$image_planet% 
Gui, 2:Add,Text, x712 y56 w141 h137, %$output_planet% 
Gui, 2:Font 
Gui, 2:Add,Picture, x696 y296 w137 h129, %$image_oppcomp% 
Gui, 2:Add,Text, x715 y312 w108 h97, %$output_oppcomp% 
Gui, 2:Font 
Gui, 2:Add,Button, x408 y472 w97 h41, %$button_close% 
Gui, 2:Font 
Gui, 2:Show, x184 y104 w906 h563, Trial v2 "
)
msgbox, % list
msgbox, % _upshift(list, $shift)

_upshift(list, line)
 {
   items := {}
   loop, parse, list, `n
    {
      items.insert(a_loopfield)
    }
   loop, % items.maxindex()
    {
      if (items[a_index] = line)
        {
          items.remove(a_index)
          items.insert(a_index - 1, line)
        }
    }
   loop, % items.maxindex()
    {
      out .= items[a_index] . "`n"
    }
   return rtrim(out, "`n")
 }
But when I use the new code and change to the fileread variable it just doesn't work. This doesn't work:

Code: Select all

$final = C:\SCRIPTING\AutoHotkey\AstrologistAutoHotkey\final.ahk
$shift = Gui, 2:Font

fileread, list, %$final%

msgbox, % list
msgbox, % _upshift(list, $shift)

_upshift(list, line)
 {
   items := {}
   loop, parse, list, `n
    {
      items.insert(a_loopfield)
    }
   loop, % items.maxindex()
    {
      if (items[a_index] = line)
       {
         items.remove(a_index)
         items.insert(a_index - 1, line)
       }
    }
   loop, % items.maxindex()
    {
      out .= items[a_index] . "`n"
    }
   return rtrim(out, "`n")
 }
And I know how to output the changed content to another file. I already have a working script that does all that. I'm just adding another section with this code.

Thank you so much for your patience :-)
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Swap/move lines in text file

23 Jan 2014, 18:10

i hereby testify that i tested as follows and script works as expected and stipulated: :ugeek:

Code: Select all

/*
list :=
(
"apple
apple
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape"
)
*/

fileread, list, list.txt ; list.txt resides in script dir
;fileread, list, list

msgbox, % _upshift(list, "grape")

_upshift(list, line)
 {
   items := {}
   loop, parse, list, `n
    {
      items.insert(a_loopfield)
    }
   loop, % items.maxindex()
    {
      if (items[a_index] = line)
       {
         items.remove(a_index)
         items.insert(a_index - 1, line)
       }
    }
   loop, % items.maxindex()
    {
      out .= items[a_index] . "`n"
    }
   return rtrim(out, "`n")
 }
dmg wrote:You have the basic idea, you just need to understand the syntax. Your code is what we might call pseudo code. It illustrates an idea but is far from being functional. It can be very useful when trying to explain an idea to another scripter.

The command you want is FileRead:
http://auto-hotkey.com/docs/commands/FileRead.htm

It reads the entire contents of a plain text file into a variable to be operated on. I say plain text file simply to mean any fine that contains characters with no formatting info included. (I apologize if I explain something you already know. I have no way of knowing what you understand or don't, so please do not think me condescending)

The portion of my code that contains the list:

Code: Select all

list :=
(
"apple
apple
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape"
)
Is just assigning static text to the list variable. The () are what is called a continuation section, meaning it allows the content on multiple lines to be added to the variable with line breaks in tact. Since you will be using a command to get the var content you don't need that part of the code at all.

Here is my code with the FileRead command added:

Code: Select all

fileread, list, filename

msgbox, % _upshift(list, "grape")

_upshift(list, line)
 {
   items := {}
   loop, parse, list, `n
    {
      items.insert(a_loopfield)
    }
   loop, % items.maxindex()
    {
      if (items[a_index] = line)
       {
         items.remove(a_index)
         items.insert(a_index - 1, line)
       }
    }
   loop, % items.maxindex()
    {
      out .= items[a_index] . "`n"
    }
   return rtrim(out, "`n")
 }
If you replace the filename parameter with the path to your file, and set the line you want moved, it should work. But even this will only display the changed content in a msgbox. You will probably want to output the changed content to another file, right?
User avatar
AlphaBravo
Posts: 476
Joined: 29 Sep 2013, 22:59

Re: Swap/move lines in text file

23 Jan 2014, 19:37

Code: Select all

list := 
(
"apple
apple
rhubarb
grape
rhubarb
grape
banana
apple
rhubarb
grape"
)

MsgBox % RegExReplace(list, "s)(.*?)(\V+)(\r?\n)(grape)", "$1$4$3$2")
return
User avatar
dmg
Posts: 282
Joined: 02 Oct 2013, 01:43
Location: "Twelve days north of Hopeless and a few degrees south of Freezing to Death"
Contact:

Re: Swap/move lines in text file

23 Jan 2014, 21:56

@Guest10:
Thank you kindly for trying it out.

@AlphaBravo:
Thanks for the input but I am pretty sure if kiwichick is having trouble with variables then RegEx may pose an additional challenge...

@kiwichick:
Yikes! I have been over your code several times and I can't find a problem. Everything checks out except the output of the FileRead command. It is getting the file content but for some reason the function I wrote does not work on it correctly. I will play with it some more and trace through the entire thing later. Sorry for the delay, and bear in mind that your code appears to be fine. It is MY code that is misbehaving. :D
"My dear Mr Gyrth, I am never more serious than when I am joking."
~Albert Campion
------------------------------------------------------------------------
Website | Demo scripts | Blog | External contact

Return to “Ask For Help”

Who is online

Users browsing this forum: Google [Bot], killall4u, LuanMts, yogurtpixel and 142 guests