Version 1.0 breaks some of my scripts

Help
Neil Hall
2014-04-03
2014-04-04
  • Neil Hall
    Neil Hall
    2014-04-03

    I have several scripts where I just want to change the first occurrence of a string. On the old version,

    editor.pyreplace(old, new, 1)
    

    did this quite happily. Having dutifully changed all my "pyreplace"s to "rereplace" the new

    editor.rereplace(old, new, 1)
    

    does nothing, so I had a look at your new documentation and tried

    editorrereplace(old, new,,,, 1)
    

    and

    editor.rereplace(old, new, , , , 1)
    

    and several variations thereof, and none of them work. So how do I do this?

    A related problem that's been bugging me for a while: your documentation doesn't say how to pass more than one flag to rereplace.

    Thanks for your help.

     
  • editor.rereplace(old, new, 0,0,0,1)
    

    As far as I know, there's no syntax in python to "skip" arguments, without using named arguments, which the N++ interface doesn't support. Therefore, you need to supply arguments for "skipped" arguments in order to supply a count argument. Flags as 0 is default, and passing 0 for start and end automatically searches the whole document.

    The order of the arguments has changed from pyreplace to rereplace, as the flags were seen to be more useful than a count, and it was more likely that people want to search within a range (e.g. in the current selection) than for a particular count of replacements. I'm sorry you're caught in the small group that uses count and not flags/start/end, hence the additional parameters.

    The flags is a bitwise set, which just means that each flag is a "bit" value, so the first flag is 1, the second 2, the third 4, the fourth 8, the fifth 16 and so on. The short answer therefore, is just to "OR" the flags together with the pipe (|) symbol. You can in some cases add the flags together, but OR is better.

    For example:

    import re
    
    flags = re.DOTALL | re.IGNORECASE
    editor.rereplace('abc.*123', 'abc123', flags)
    

    Read on for an explanation if you're interested:

    re.DOTALL is 16, and re.IGNORECASE is 2.

    16 | 2 is 18.

    16 + 2 is also 18.

    However,

    16 | 2 | 2 == 18
    16 + 2 + 2 == 20

    For the flags that have an impact on the replace functions, it doesn't matter, but there are cases where one flag actually "includes" other flags. Imagine there was a convenience flag that included DOTALL and IGNORECASE - let's call it "DOTALLCASEINSENSITIVE", it's value would be 18. If we we're quite sure what effect this had, and we wanted to include the IGNORECASE flag anyway, we could use DOTALLCASEINSENSITVE | IGNORECASE, and know that IGNORECASE is definitely included, even if DOTALLCASEINSENSITIVE includes it.

    If we'd simply added them, DOTALLCASEIGNORE + IGNORECASE, then we end up with 20, which would be the bit value 16 with the bit value 4. Notice that our IGNORECASE flag (value 2) has actually been switched off!

                            16   8    4   2   1
    --------------------------------------------- 
    IGNORECASE               0   0    0   1   0
    DOTALL                   1   0    0   0   0
    DOTALLCASEINSENSITIVE    1   0    0   1   0
    
    DOTALL | IGNORECASE      1   0    0   1   0
    DOTALLCASEINSENSITVE
             | IGNORECASE    1   0    0   1   0
    
    DOTALLCASEINSENSITVE
             + IGNORECASE    1   0    1   0   0
                (= 20)
    

    Therefore, it's best practice to always "OR" flags together

    There are a number of cases of this sort of binary arithmetic in the Scintilla library, for example the scintilla callback for MODIFIED has a modificationType argument, which is a set of flags represented as an integer.

    I hope that makes it a bit clearer.

    Cheers,
    Dave.

     
  • Neil Hall
    Neil Hall
    2014-04-04

    Thanks for that, your fix worked splendidly.

    Bit flags and bit masks - oh, that brings back memories! IBM mainframes more than 40 years ago, examining the Assembler code produced by the Fortran compiler - even writing some Assembler myself to interface better with the operating system from the two Algol compilers (IBM and Delft) available on the mainframe. Those machines were so expensive we cared about every byte and clock cycle used. Hard to believe, but the laptop I'm typing on now is about a million times faster and a thousand times cheaper than those machines.

    Well, nowadays I'm retired and haven't done any serious programming for about 15-20 years, but intend to learn Python properly. So far I'm using it just to string together a series of regular expression "find/replace"s - just that on its own is remarkably powerful and useful, but I'm at the stage now where I do need to start learning the language properly. Like any programming language, the hard bit isn't really the language itself, but all the ancillary bits(! pun not intended) needed to interface it with other systems and getting to know the available libraries.

    Thnks,
    Neil

    PS. Thanks also for the new version, it is noticeably faster (much faster) and should, I think, prove to be easier to use, once I've sorted out the transition glitches.

    Much to my surprise, I replaced all the pymlreplaces, just got rid of the ", 0, Editor.INCLUDELINEENDINGS)"s and it worked! Well, except for one or two places where it gets confused by leading or trailing spaces at the beginning/end of a line, but I'm sure I can sort those out.