(((This is a bug)) since the first day) I join Notepad++
-
Please use Ctrl+B to detect what is wrong.
Correct:
( (Here is a bug) since the ( (first day) ) I joined Notepad++ ( ( (and found ( (and reported
for version 7.6) ), but it gets no corrections) for version 7.8) ) and (I could not find my post any more) ).Errors:
((Here is a bug) since the ((first day)) I joined Notepad++ (((and found ((and reported
for version 7.6)), but it gets no corrections) for version 7.8)) and (I could not find my post any more)).My temporary solution is adding a space between any contiguous ‘(’ or ‘)’.
-
@W-TX said in (((This is a bug)) since the first day) I join Notepad++:
(I could not find my post any more) ).
Not all that difficult: https://community.notepad-plus-plus.org/topic/17676/control-b-does-not-work-correctly-why
-
@Alan-Kilborn Thank you.
-
@W-TX Even though on the first day I used Notepad++ I found the Control+b bug, it is the most efficient text editor, second to none!
-
Hello, @w-tx, @alan-kilborn and All,
The default
CTRL + B
behavior is-
If caret is, either, right before or right after a starting parenthesis
(
aCtrl + B
action moves the caret right before its matched ending parenthesis)
-
If caret is, either, right before or right after an ending parenthesis
)
aCtrl + B
action moves the caret right before its matched starting parenthesis(
Anyone easily understands that, in case of jointed parentheses
((
, or))
or, even,)(
there’s a problem becauseCtrl + B
operates, both, if you place the caret before of after a parenthesis :-((Logically, the correct behaviour should be :
-
If caret is, either, right after a starting parenthesis
(
aCtrl + B
action moves the caret right before its matched ending parenthesis)
-
If caret is, either, right before an ending parenthesis
)
aCtrl + B
action moves the caret right after its matched starting parenthesis(
Now, I found a work-around to get a logical behavior ;-)) As you know, regular expressions are my beloved hobby ;-)). So, using a resursive regex construction solves the wrong behavior of
Ctrl + B
, in case of consecutive parentheses !First, I’m going to explain the regex. This surely will seem a bit tricky to some people but don’t panic ! In the second part of this post, I will discuss of some very practical combinations with the regex and some keyboard actions to simulate the correct
Ctrl + B
behaviour ;-))
The magic search regex is :
(?x) \( ( [^()]+ | (?0) )* \)
What’s that means :
-
First, the
(?x)
in-line modifier forces the regex engine to ignore any space character and new-line chars in the regex and, incidentally, to add comments -
Then, the part
\(
looks for a literal starting parenthesis(
, because of the escaped form -
Similarly, at the end, the
\)
part searches for a literal ending parenthesis)
, for the same reason -
Between this two parentheses, the part
( [^()]+ | (?0) )*
represents a group, possibly empty, due to the*
quantifier, which may be repeated as many as possible, containing two alternatives :-
The part
[^()]+
which grasps any non-null range of characters, different from parentheses(
and)
-
The part
(?0)
which is a recursive call to the entire regex pattern
-
How this recursion process works ?
Let suppose, the MAIN part of the regex ( SPACES are supposed to be IGNORED ) - The regex \( ( [^()]+ | (?0) )* \) is SIMILAR to : ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯ \______________ =(?0) _____________|_______________ - the regex \( ( [^()]+ | \( ( [^()]+ | (?0) )* \) )* \) which is, itself, SIMILAR to : ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|¯¯¯¯¯¯¯¯¯¯¯¯¯ \_______________ = (?0) _____________|_______________ - the regex \( ( [^()]+ | \( ( [^()]+ | \( ( [^()]+ | (?0) )* \) )* \) )* \) which is, itself, SIMILAR to : and so on ...
Now, we can still improve our regex, by using :
-
A non-capturing group, as we don’t need group
1
contents -
A possessive quantifier, in order that the range of allowed characters will be treated as an atomic range of chars, where backtracking is forbidden. We can do that because, in PCRE regexes, any recursion call is treated in an atomic way, anyway !
So our magic final regex is :
(?x) \( (?: [^()]++ | (?0) )* \)
In order to assign a shortcut to our regex, here are two macros, which you’ll have to insert in the
<Macros>....</Macros>
section of you activeshortcuts.xml
configuration file. They allow search of well-balanced blocks of parentheses in downwards (ALT + B
shortcut ) and backward direction (Alt + Shift + B
shortcut ) with the wrap-around behavior<Macro name="Regex_Forward" Ctrl="no" Alt="yes" Shift="no" Key="66"> <!-- ALT + B shortcut --> <Action type="3" message="1700" wParam="0" lParam="0" sParam="" /> <Action type="3" message="1601" wParam="0" lParam="0" sParam="(?x) \( (?: [^()]++ | (?0) )* \)" /> <Action type="3" message="1625" wParam="0" lParam="2" sParam="" /> <!-- REGULAR expression search mode --> <Action type="3" message="1702" wParam="0" lParam="768" sParam="" /> <!-- DOWNWARD search --> <Action type="3" message="1701" wParam="0" lParam="1" sParam="" /> <!-- Hit on the FIND NEXT button --> </Macro> <Macro name="Regex_Backward" Ctrl="no" Alt="yes" Shift="yes" Key="66"> <!-- ALT + SHIFT + B shortcut --> <Action type="3" message="1700" wParam="0" lParam="0" sParam="" /> <!-- INITIALIZATION --> <Action type="3" message="1601" wParam="0" lParam="0" sParam="(?x) \( (?: [^()]++ | (?0) )* \)" /> <Action type="3" message="1625" wParam="0" lParam="2" sParam="" /> <!-- REGULAR expression search mode --> <Action type="3" message="1702" wParam="0" lParam="256" sParam="" /> <!-- BACKWARD search --> <Action type="3" message="1701" wParam="0" lParam="1" sParam="" /> <!-- Hit on the FIND NEXT button --> </Macro>
If, for testing, you don’t want to use a macro, here is an alternate method :
-
Open the Find dialog
-
Type in the regex
(?x) \( (?: [^()]++ | (?0) )* \)
, in the Find what: zone -
Untick the
Backward
option, if necessary -
Select the
Regular expression
search mode -
Hit the
Find Next
button -
Whatever the result, close the Find dialog with the
ESC
key -
Open one of your code files, containing some parentheses
=> Now, from caret position :
-
Any hit on the
F3
shortcut, will select the next well-balanced block of parentheses -
Any hit on the
Shift + F3
shortcut, will select the previous well-balanced block of parentheses
Practical example :
Let’s assume the simple text, below. Note that I wrote it in a single line for readability, but this text could be displayed in several lines, either !
123(456(()7890)12(345((678)((901)2(34567)890(12345)678)90123456((7890(12345)67))8901)2345))6789 >< >< >< 3rd 2nd 1st
-
Move the caret to the
"1st"
position, so between the0
digit and the(
-
Hit the
F3
key :
=> The
(12345)
block, with its parentheses, is selected. As you can see, this operation is similar to theCtrl + Alt +B
( Select All Between Matching Braces ).-
At this point, you may, either :
-
Hit the
Ctrl + C
shortcut, if you need to copy that well-balanced block of parentheses somewhere else -
Hit the
Right
arrow key to suppress selection and place the caret right after the ending)
-
Hit the
Left
arrow key to suppress selection and place the caret right before the starting(
-
You may, instead, hit the
CTRL + B
shortcut for the similar above operation !
-
Now, let’s try some searches, in both directions :
-
Move the caret to the
"2nd"
position, so between the)
and the9
digit- Hit the
F3
key
- Hit the
=> You’ll notice that the regex finds the next largest well-balanced block, which is
((7890(12345)67))
- Hit the
Shift + F3
shortcut to search in backward direction
=> The inner block
(7890(12345)67)
is selected, as expected- Hit, again, the
Shift + F3
shortcut
=> The inner block
(12345)
is then selected- Hit, again, the
Shift + F3
shortcut
This time, as no more inner block exists, it jumps back to previous largest block
((901)2(34567)890(12345)678)
At this point,
3
possibilities :- If you hit the
F3
key
=> you’ll get the
((7890(12345)67))
block again- If you’ll hit, successively, on the
right
then theleft
key and, finally, theShift + F3
shortcut
=> The closest inner block, near the end of present block, is selected
(12345)
- If you’ll hit, successively, on the
left
then theright
key and, finally, theF3
shortcut
=> The closest inner block, near the start of present block, is selected
(901)
After a while , I’m quite sure you’ll get acquainted, very quickly, to this regex behaviour !
-
Now, move the caret to the
"3rd"
position, so between the two starting parentheses((
-
Hit the
F3
key
=> As expected, it selects the empty block
()
- Hit the
F3
key again,
=> This time, the regex selects the penultimate largest block of my example, so the well-balanced block :
(345((678)((901)2(34567)890(12345)678)90123456((7890(12345)67))8901)2345)
To end with, may be you could also give it a try to :
-
The regex
\((?:[^()]++|(?0))*\K\)
which only matches the ending matched parenthesis)
-
The regex
\((?:[^()]++|(?0))*\)\K
which matches the zero-length position, right after the ending matched parenthesis)
Best Regards,
guy038
P.S. :
Of course, this recursive regex can be used with an other couple of delimiters, which could be, for instance :
-
{
and}
=> The recursive regex would be(?x) \{ (?: [^{}]++ | (?0) )* \}
-
[
and]
=> The recursive regex would be(?x) \[ (?: [^][]++ | (?0) )* \]
-
<
and>
=> The recursive regex would be(?x) < (?: [^<>]++ | (?0) )* >
-
-
This is the patch I prepared for myself 4 (or more) years ago.
Initially I tried to contribute it into Notepad++ main repository but after giving up I started maintaining my own build. Still using it based on ver 6.7.8.2. -
Managed to dig the ticket I posted on sourceforge.
-
@gstavi said in (((This is a bug)) since the first day) I join Notepad++:
Managed to dig the ticket I posted on sourceforge.
In the linked ticket, @donho said:
The current behaviour is preferable comparing with the one you suggested.
He is perhaps unique in liking the behavior! :-( Of course, deciding you like the behavior is much easier than doing something to change it. :-)