Replacing number with another Incrementing #
-
@astrosofista
Hi!.. Sorry for the late reply…
Oh… thank you for explaining…
But the number line will be long… From 40001 to 70000… :( -
What is Regex: a language for describing a formula to find patterns in a text
What is Regex not: A calculator, a painting application, … or a replacement for a programming language.
Whenever it is necessary to calculate something based on its results,
then a programming language should be used.
However, this does not mean that it is not possible with a regex,
but creating a regex in such scenarios is usually complex and
only works for this particular case. -
Inspired by Eko’s posted script HERE I have created the following Pythonscript (see below) to help accomplish the goal of this current thread.
Here’s how it would be applied in this case (2-phase solution):
Part 1 of 2:
-
Run the script (with your data file as the active tab in Notepad++).
-
Specify
^\d{3}(?=#)
in the input box that appears. Press OK. -
At this point all of the items to be incrementally replaced should be selected.
Now for part 2 of 2:
-
With the data still multiselected, press
Alt+c
to invoke theColumn editor
. -
Tick
Number to insert
and specify your starting number in the `` box. -
Specify your
Initial number
(e.g.40001
) andIncrease by
number (e.g.1
). -
Press OK and your text should be transformed as desired.
The script:
from Npp import editor, notepad class T19343(object): def __init__(self): if editor.selectionIsRectangle(): return if editor.getSelections() == 1: if editor.getSelectionEmpty(): scope_starting_pos = 0 scope_ending_pos = editor.getTextLength() else: scope_starting_pos = editor.getSelectionStart() scope_ending_pos = editor.getSelectionEnd() while True: title = 'SELECT ALL matches in ' title += 'ENTIRE FILE' if editor.getSelectionEmpty() else 'SELECTED TEXT' user_regex_input = notepad.prompt('REGEX to search for: (will result in multiple selections)\r\n(hint: if need to, start regex with \Q to do a "normal" search)', title, '') if user_regex_input == None: return # user Cancel try: # test user_regex_input for validity editor.research(user_regex_input, lambda _: None) except RuntimeError as r: notepad.messageBox('Error in search regex:\r\n{0}\r\n{1}\r\n\r\nYou will be prompted to try again.'.format(user_regex_input, str(r)), '') else: break match_list = [] editor.research(user_regex_input, lambda m: match_list.append(m.span(0)), 0, scope_starting_pos, scope_ending_pos) #print(match_list) if len(match_list) >= 1: (first_match_anchor_pos, first_match_caret_pos) = match_list[0] # set the FIRST selection and bring it into user's view: editor.setSelection(first_match_caret_pos, first_match_anchor_pos) editor.scrollRange(first_match_anchor_pos, first_match_caret_pos) # remember top line of user's view, for later restore first_line = editor.getFirstVisibleLine() if len(match_list) >= 2: editor.setMultipleSelection(True) # in case not enabled in the Preferences # add in all the remaining selections: for (match_anchor_pos, match_caret_pos) in match_list[1 : ]: editor.addSelection(match_caret_pos, match_anchor_pos) editor.setFirstVisibleLine(first_line) elif editor.getSelections() > 1: delimiter = notepad.prompt('Delimit individual copied selections with:\r\n(leave empty to delimit with line-endings)', 'Copy selections to clipboard', '') if delimiter != None: if len(delimiter) == 0: delimiter = '\r\n' accum_list = [] for sel_nbr in range(editor.getSelections()): accum_list.append(editor.getTextRange(editor.getSelectionNStart(sel_nbr), editor.getSelectionNEnd(sel_nbr))) editor.copyText(delimiter.join(accum_list)) #editor.setEmptySelection(editor.getCurrentPos()) notepad.messageBox('Results are now in clipboard', '') if __name__ == '__main__': T19343()
-
-
I should mention two more things about the script:
-
The scope of the search can be limited by making (one) selection of a stream of text before running the script
-
If the script is run a second time, i.e., while the multiselections from the first run are still active, it provides a mechanism to copy all of the matches (selections) to the clipboard.
-
-
Thank you for providing the detailed explanation…
-
@raizkie19 said in Replacing number with another Incrementing #:
But the number line will be long… From 40001 to 70000… :(
Hi @raizkie19, @Ekopalypse, @Alan-Kilborn and All
As @Ekopalypse said, regex can’t do math, but there are workarounds to simulate some common operations. So, as an alternative to @Alan-Kilborn’s script and in case you are not allowed to install the Python plugin, let me suggest you the following method, which is based on previous posts.
Please try the following:
Open a new tab in
Notepad++
(Ctrl + N
)
Type in aspace
and then press theEnter key
Open theReplace
dialog (Ctrl + H
)
Set the following fields as follows (Copy/Paste):Find what:
\R
Replace with:\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
Only select the
Wrap Around
option and theRegular expression search
mode
Click5 times
theReplace All
button in order to get 32768 (= 2^15) lines with a blank space
Close theReplace
dialogPress
Ctrl + Home
to go to very beginning of the file.Now, open the
Column editor
(Edit
->Column Editor…
, orAlt + C
)Check the
Number to Insert
option
Type100
in theInitial number
field
Type1
in theIncrease by
field
Leave the optionsRepeat
andLeading zeros
empty
The format is decimal, by default
Click on theOK
buttonPlace the caret at the
beginning of the file
and then pressEnd
to put it after theblank space
that follows100
.Again, open the
Column editor
(Edit
->Column Editor…
, orAlt + C
)Check the
Number to Insert
option
Type40001
in theInitial number
field
Type1
in theIncrease by
field
Leave the optionsRepeat
andLeading zeros
empty
The format is decimal, by default
Click on theOK
buttonThe replacement list is done. You should have got a list as to this one:
100 40001 101 40002 102 40003 103 40004 104 40005 [...] 32864 72765 32865 72766 32866 72767 32867 72768 32868 72769
Copy
the whole list (Ctrl + A
)Open a copy
of the file to be changed.
Go to thelast line
.
PressEnter
, then type===
(three equal signs
) and pressEnter
again.
Paste
the list to get the following:30000# A tuber that can be fried, baked, boiled mashed, even eaten. === 100 40001 101 40002 102 40003 [...]
Return to the
first line
of the file (Ctrl + Home
)
Open theReplace
dialog (Ctrl + H
)
Deselect all options except theRegular expression search
mode
Set the following fields as follows (Copy/Paste):Search:
(?s)^(\d+)(?=#\R.*?===.*?\1 +(\d+))
Replace:?1$2
Now, the last action:
Click on theReplace All
button
Close deReplace
dialog.That’s all. All the numbers should have been changed.
Best Regards.
-
Now THAT is a serious workaround, for the truly desperate. :-)
-
@Alan-Kilborn said in Replacing number with another Incrementing #:
Now THAT is a serious workaround, for the truly desperate. :-)
Yep, looks as a quite hard task, but actually isn’t. It would be easier to deliver if the macro feature could record Column Editor outputs.
Later will try your nice Python script.
-
@Alan-Kilborn said in Replacing number with another Incrementing #:
Specify ^\d{3}(?=#) in the input box that appears. Press OK.
Tested and worked fine on sample text :)
However, I found a potential failure. OP told us that he wanted to replace 30,000 numbers, so if these grow by one, as the sample text suggests, then the regex you provided will fail to match four or five digit numbers.
If this is the case, then as you know, expressions like
^\d{3,5}(?=#)
or^\d+(?=#)
will match all the numbers. -
I found a potential failure.
True, but also kind of obvious. :-)
Plus, I should have used “e.g.” on that part of it, like I did in 2 other places.But yes, the OP may not be versed in regex, and may not know how to specify a solution that covers all his cases, so thanks for the pick-me-up on that.
For me, it was more about publishing the script, which I had sitting unfinished in my N++ tabs ever since @Ekopalypse published his original script (which only selected multiple occurrences of static text).
-
@Alan-Kilborn said in Replacing number with another Incrementing #:
For me, it was more about publishing the script
Rest assured your script is a nice and useful improvement, since it allows users to make more complex selections with greater flexibility.
Thank you for sharing it with us :)
-
Hi @raizkie19, @Ekopalypse, @Alan-Kilborn, All
I have just realised that, given the regularity of the problem in question, it can also be stated as a mathematical operation, a simple addition. This approach, which perhaps was the one that @ekopalypse had in mind in his post above, gives rise to a third alternative, simpler and more direct than the two posted so far, since although it still requires the Python plugin and a regex, it doesn’t need any list created with the Column Editor.
The following script is a very minor adaptation of a code posted by @ekopalypse to solve a similar problem, so all credits belongs to him:
from Npp import editor def add_raizkie_number(m): return int(m.group(0)) + 39901 editor.rereplace('\d+(?=#)', add_raizkie_number)
So, @raizkie19 hope you can test it and see if it deliver the expected outcome. It worked fin here.
Have fun!
-
@astrosofista said in Replacing number with another Incrementing #:
very minor adaptation of a code posted by @ekopalypse to solve a similar problem
so all credits belongs to himActually, I think all of the credit goes back to the Pythonscript documentation!
Note, though:
number
should beint
in the documentation! -
More specifically, I have modified the result of calling help(editor.rereplace) in the PythonScript console.
>>> help(editor.rereplace) Help on method rereplace: rereplace(...) method of Npp.Editor instance rereplace( (Editor)arg1, (object)searchRegex, (object)replace) -> None : Regular expression search and replace. Replaces 'searchRegex' with 'replace'. ^ and $ by default match the starts and end of the document. Use additional flags (re.MULTILINE) to treat ^ and $ per line. The 'replace' parameter can be a python function, that recieves an object similar to a re.Match object. So you can have a function like def myIncrement(m): return int(m.group(1)) + 1 And call rereplace('([0-9]+)', myIncrement) and it will increment all the integers.
-
@Alan-Kilborn said in Replacing number with another Incrementing #:
Note, though: number should be int in the documentation!
That documentation bug was fixed in v1.5.3 in February.
v1.5.4 has been released since, with the fix to the getLanguageDesc() historical bug which we finally reported in #146. -
May it be, mine was just a disclaimer, as I know almost nothing about Python :)