newbee, macros and basic algorithm with Python Script
-
@mpheath’s contribution made me realize OP’s request might pertain, not to a single file with many [song] records as I had concluded, but rather to many single-song files.
My interpretation was based on OP only naming one file (but I now see the intent might have been that it be treated as a template), and having a start-of-record element in the samples (and in compsci, the word ‘file’ sometimes refers to an abstract record rather than a named disk file).
So if there are actually many files to process, my suggestion that
… everything you want done can be accomplished with a series of Find-and-Replace operations.
is wrong.
OP did not explicitly say every (disk) file contains exactly one record. If there are files containing multiple song records, both of @mpheath’s solutions would need a bit of work to handle per-record processing.
-
This post is deleted! -
I cannot edit my last post so the correction is done here.
The PythonScript I posted can read the edit pane with
\r\n
EOLs. The replaced text may have\n
EOLs. If\r\n
is wanted, then change this section:# Create text from lines. text = '' for line in lines: text += line[1] + '\n' return text
to
# Create text from lines. text = '' for line in lines: text += line[1] + '\r\n' return text
This will not be a problem with the standalone script as Python will convert
\n
to\r\n
on write. -
This post is deleted! -
This post is deleted! -
This post is deleted! -
This post is deleted! -
I’m sorry.
I really have problems with posting and editing in this forum : bots are thinking I produce spam :( -
I’m very grateful for the attention you give to my problem.
I will try to precise it.1 - I have over 5000 song’s folder which contains several files (.ogg, .mid, .bpm, .ini…). In each folder, there is an unique file ‘song.ini’. I used to navigate manually in this 5000 folders : it take me a long long time but I have no alternative for now.
In each folder, I open the ‘song.ini’, operate on it launching with a key shortcut a unique macro to save time on basic manipulations (ideally 1 macro or 2 or 3 if there is no way to do an unique macro due to my incapacity to implement conditional tests), check visually the modifications and IF ‘success’ {save/close (with ‘ctrl’ + ‘w’ and ‘enter’ to validate)} ELSE {close file without saving in order to re-operate it manually correctly following}.2 - I would love to find a solution with a basic macro which I can set up myself with your help. It would be easier for everybody.
find: (artist = .?\R)(name = .?\R)
repl: $2$1Your 2 lines “open my mind”…
First you make me realize I can open replace window whith ‘ctrl’ + ‘h’ (it could be useful for me in the future).
Second, I discover ‘.*?\R’ and ‘$2$1’. This expressions are perhaps multiple and powerful. Where can I found information on that kind of expressions ?I think my problem can’t be solve with REPLACE.
I just have to :IF (find() == true) then MOVE a line; ELSE then CREATE a line;
I re-wrote my algorithm to simplify it :
Open : 'song.ini' Desactivate 'back line auto' in 'display' Desactivate numeric keypad Start macro # move "name =" If (find("name =") == true) : cut ("name =" line with precedent line break) and paste it after ("[song]" line); Else : create a line after ("[song]" line) and write "name = "; # move "artist =" If (find("artist =") == true) : cut ("artist =" line with precedent line break) and paste it after ("name =" line); Else : create a line after ("name =" line) and write "artist = "; # move "album =" If (find("album =") == true) : cut ("album =" line with precedent line break) and paste it after ("artist =" line); Else : create a line after ("artist =" line) and write "album = "; # Do the same routine to move "genre = ", "year = ", "track = ", "loading_phrase = ", "charter = ", "frets = " # And the last # move "song_length =" If (find("song_length =") == true) : cut ("song_length =" line with precedent line break) and paste it after ("frets =" line); Else : create a line after ("frets =" line) and write "song_length = "; # move cursor to the first line to make easier the visual check before close/save or close/non-save 'ctrl' + 'a'; # select all the lines 'left arrow'; # move cursor to the start of 'song.ini' End macro
Any proposition ?
3 - Looking at @mpheath’s proposition (which inevitably go away of my algorithm). The second proposition without open editor is not “satisfying” me because I can’t check after modifications and cancel them if necessary. Concerning the first proposition (which is surely the way I have to go), I hope you could take mention of my problem’s details upper to amend this code in consequences.
Otherwise, could you explain more the sense of this lines :
3.1 -lines = [[-1, line.replace('\n', '')] for line in text.splitlines()]
3.2 -
line[1].startswith(item + ' = '):
3.3 -
lines.append([-1, item + ' = '])
3.4 -
if line[0] == -1: if line[1].startswith('[') or line[1].startswith(item + ' = '): line[0] = index index += 1
3.5 -
lines.sort(key=lambda x: x[0])
3.6 -
if __name__ == '__main__': text = ini_reindex() if text != '': editor.setText(text)
Best regards and thanks a lot.
-
Note: The 2nd script can be made recursive with changing:
for file in glob.iglob('*.ini'):
to
for file in glob.iglob(r'**\song.ini', recursive=True):
This will do
song.ini
in current and subdirectories.Now your questions answered:
3.1 -
lines = [[-1, line.replace('\n', '')] for line in text.splitlines()]
Creates a list of lists like
[[-1, 'Line 1'], [-1, 'Line 2'], [-1, 'Line 3'], ...]
The
-1
will be replaced with numbers to order the lines later for sorting.3.2 -
```line[1].startswith(item + ' = '):```
item
is each ofpresets
list of['name', 'artist', 'album', 'genre', 'year', 'track', 'loading_phrase', 'charter', 'frets', 'song_length']
So 1st one it trys to match is start with
name =
. Then triesartist =
… until all items are tried. Ifbreak
does not occur, then theelse
happens and theitem
key is added to the list.3.3 -
```lines.append([-1, item + ' = '])```
lines
is a list and.append
is a method to add to the list.Like in 3.2, if the
else
ocurrs for not finding examplename =
, then[-1, 'name = ']
is added to the list.3.4 -
if line[0] == -1: if line[1].startswith('[') or line[1].startswith(item + ' = '): line[0] = index index += 1
This is lines with a
-1
index, not given a line number yet. If starts with[
(section header) oritem + ' = '
assign a line number toline[0]
, which is replace the-1
with a line number.index
is the line number soindex += 1
increments the number by adding1
.3.5 -
```lines.sort(key=lambda x: x[0])```
Sorting the list of lists
lines
by the first element[0]
.lambda
is like a nameless function. The sort will look at example[[2, 'Line 2'], [1, 'Line 1']]
so it sees the1
and shifts it into 1st place and then2
for 2nd place. This gets the list into the order that is wanted.3.6 -
```if __name__ == '__main__': text = ini_reindex() if text != '': editor.setText(text) ```
__name__
is the name of the running script. If named__main__
, run the following code.ini_reindex()
is the function call and the returned value is saved intext
. If the text returned is not an empty string, then calleditor.setText(text)
to replace edit pane contents with the value oftext
. -
@mpheath Thanks for the explanations.
I think I’m disturbed by the fact that variables are not declared. For example, I was confused between ‘line’ and ‘lines’.
Moreover, what is ‘line[0]’ ? The ‘line’ number ? The first character of ‘line’ ? The first element of ‘line’ ?I’m gonna comment your original code with your explanations in order to improve readability and my comprehension too. I will work on it during this next week and I’ll reply as soon as I progress.
Read you soon.
-
@mpheath said in newbee, macros and basic algorithm with Python Script:
The replaced text may have \n EOLs. If \r\n is wanted, then change this section
A smooth way to handle this would be, using your line of code as a basis:
text += line[1] + ['\r\n', '\r', '\n'][editor.getEOLMode()]
This will put the correct line-ending on according to the current tab’s setup.
-
I don’t know that this is an appropriate forum for teaching someone the ins and outs of programming Python for solving a very specific problem.
While I appreciate that there are some tie-ins to editor objects to get and set the active tab’s text, really this is just a straight Python programming problem.
As such, since @mpheath seems interest in helping @Mathias-Lujan with this, can I suggest they get together using the forum’s direct chat feature and expand/explain the effort in that way?
Use this button to do so:
-
@alan-kilborn I think we are near to the solution. Let me just understand and implement it. I don’t want to learn Python programming, I just want solve my problem.
As I said :
" I would love to find a solution with a basic macro which I can set up myself with your help. It would be easier for everybody.
[…]
I think my problem can’t be solve with REPLACE.
I just have to :
IF (find() == true)
then MOVE a line;
ELSE
then CREATE a line; "So, macro N++ or Python Script to solve my problem ?
-
@mathias-lujan said in newbee, macros and basic algorithm with Python Script:
I don’t want to learn Python programming, I just want solve my problem.
That’s fine, for you. But this forum doesn’t take kindly to those that don’t want to learn. It means someone else has to (choose to) do your work for you. It also probably means that when you need changes, however small, you’ll come here, expecting more free work done on your behalf.
-
@mathias-lujan said in newbee, macros and basic algorithm with Python Script:
I never used Python and it would take me a lot of time to code my basic algorithm. For a regular, this will probably only take an hour or less.
I wrote my basic algorithm (Algorithme rename.txt) and I hope somebody could code it entirely or help me for the Python part.When I wrote :
I don’t want to learn Python programming, I just want solve my problem.
I would say : I just want to solve my problem with basic Python programming, not to code in general.
Anyway, I feel that most of the work is already done by @mpheath and I just have to implement and test his code. I will try to do that this week.
Thanks again for all. -
@mathias-lujan
Maybe this is mustard after the meal as we say in Dutch, but here is another solution to your problem:# -*- coding: utf-8 -*- from __future__ import print_function # Python 2.7 from Npp import * def moveLine(stringToBeMoved, targetString): try: startW, endW = editor.findText(FINDOPTION.WHOLEWORD, 0, lenFile, stringToBeMoved) except: line = stringToBeMoved #notepad.messageBox(stringToBeMoved + ' not found') else: lineNmbr = editor.lineFromPosition(startW) line = editor.getLine(lineNmbr).replace('\r\n', '') editor.deleteLine(lineNmbr) try: startW, endW = editor.findText(FINDOPTION.WHOLEWORD, 0, lenFile, targetString ) except: notepad.messageBox(targetString + ' not found') return else: endLine = editor.getLineEndPosition(editor.lineFromPosition(endW)) editor.gotoPos(endLine) editor.addText('\r\n'+line) items = [ '[song]', 'name =', 'artist =', 'album =', 'genre =', 'year =', 'track =', 'loading_phrase =', 'charter =', 'frets =', 'song_length =', 'delay =', 'diff_guitar =', 'diff_bass =', 'diff_guitar_coop =', 'diff_rhythm =', 'diff_vocals =', 'diff_keys =', 'diff_bass_real =', 'diff_guitar_real =', 'diff_dance =', 'diff_bass_real_22 =', 'diff_guitar_real_22 =', 'diff_vocals_harm =', 'sysex_high_hat_ctrl =', 'multiplier_note =', 'pro_drums =', 'background =', 'last_play =' ] for i in range(0, len(items)-1): stringToBeMoved = items[i+1] targetString = items[i] moveLine(stringToBeMoved, targetString)
-
@paul-wormer
Bug: add the linelenFile = editor.getLength()
as first line to the function
moveLine
(it is the default offindText
, which is why I did not see it) -
@mathias-lujan
I tested my little script on your first example and it worked exactly the way you wanted. Today I tested the script on your second example and it works fine again, except that it fails on many undefined items (keywords).If you want any script to work you have to define a fixed set of keywords that appear in each and every one of your files. The fact that the sets of keywords change between your files makes me wonder how much coding experience you have. Any programmer understands that automatizing your editing is impossible when the keywords vary between files. When you have to introduce a separate set of keywords for every file, you may as well do the editing by hand.
-
@paul-wormer said in newbee, macros and basic algorithm with Python Script:
If you want any script to work you have to define a fixed set of keywords that appear in each and every one of your files
I don’t know that this is true. A keyword could belong to the set of undefined keywords, it just couldn’t be specially manipulated (reordered into the top grouping the OP seems to want for some keywords). It could certainly “tag along” in the reformatting effort (although apparently not in the script you wrote).