SourceForge has been redesigned. Learn more.
Close

MS Word-style case change (Shift+F3 feature): change the case of selected text from upper to lower to title

Abbas
2013-08-11
2014-11-16
  • Abbas

    Abbas - 2013-08-11

    :::python

    # MS Word has the option of changing the case of selected text by pressing Shift+F3
    # The case changes in the order: UPPER CASE, lower case, Title Case
    # It was something I was missing in Notepad++ so I wrote the following script to add the change case feature
    # Remember to associate this script with Shift+F3 key combination in the Shortcut Mapper
    
    text = editor.getSelText()
    
    if text: # Do this only if some text has been selected
        checkingFuncs = [lambda s: s.isupper(), lambda s: s.islower(),  lambda s: s.istitle(),  lambda s: True]
        alteringFuncs = [lambda s: s.lower(),   lambda s: s.title(),        lambda s: s.upper(),        lambda s: s.upper()]
        numOfFuncs = len(checkingFuncs)
    
        for i in range(0, numOfFuncs): # Iterate through the list of checking functions
            if checkingFuncs[i](text): # Check the existing case of the text
                text = alteringFuncs[i](text) # Based on the result of checking function, change the case in this order: upper->lower, lower->title, title->upper, anything else->upper
                break
    
        start = editor.getSelectionStart() # Record the start and end position of the selection
        end =   editor.getSelectionEnd()
    
        editor.replaceSel(text) # Replace the originally selected text with altered-case text, this will end the selection as well
    
        editor.setSel(start, end) # Select the newly altered text
    
     
    • Abbas

      Abbas - 2014-11-16
      # Edited to include changes suggested by Rufus in the comments
      
      text = editor.getSelText()
      
      if text:
          # tuples of check and alter functions
          functable = [
                      (lambda s: s.isupper(), lambda s: s.lower()),
                      (lambda s: s.islower(), lambda s: s.title()),
                      (lambda s: s.istitle(), lambda s: s.upper()),
                      (lambda s: True,        lambda s: s.upper())
                      ]
      
          for check, alter in functable: # Iterate through the list of checking and altering functions
              if check(text):
                  text = alter(text)
                  break
      
          start = editor.getSelectionStart()
          end = editor.getSelectionEnd()
      
          editor.replaceSel(text)
      
          editor.setSel(start, end)
      
       
      Last edit: Abbas 2014-11-26
  • Rufus V. Smith

    Rufus V. Smith - 2014-09-10

    Nicely done. The only issue I have is the need for indexing into arrays. I think it is prettier Python doing the checks and alters this way:

    functable = [  # tuples of check_function, alter_function
    (lambda s: s.isupper(), lambda s: s.lower()),
    (lambda s: s.islower(), lambda s: s.title()),
    (lambda s: s.istitle(), lambda s: s.upper()),
    (lambda s: True,        lambda s: s.upper())
    ]
    for check,alter in functable:
        if check(text): 
            alter(text)
            break
    

    You've inspired me to create a "invert case" function, because I'm forever typing labels with my caps-lock on!

    P.S. if you already have the first macro in and are a lazy typer like I am, you can just put the following line after your existing function tables:

    functable = zip(checkingFuncs, alteringFuncs)
    

    (I also like having checks and alters in a single list, so I don't have two lists to keep in sync if I decide to change one.)

     
    • Abbas

      Abbas - 2014-11-16

      Excellent suggestion, indexing into the arrays always troubled me subconsciously, and while I too am a lazy typist, the improvement in code was too good to just use the zip function. I have updated my post.

      The only change I made was assign text to the alter functions return value.

      Please continue to share suggestions. Will look forward to your script contributions as well.

      Regards,

      Abbas

       
  • Dan Padric

    Dan Padric - 2017-06-05

    Hello.

    Thank you very much for sharing this code segment. It has been very nice tool to get introduced to a few concpets relating to Python and this Add-on for Notepad++.

    I do hope you do not mind me making some contribution - hoping others will learn as much as I have. See below the small expansion.

    • Dan
    '''
    Title:      MS Word-style case change (Shift+F3 feature): 
                change the case of selected text from upper to lower to title 
    Creator:    Abbas 
    Publish:    https://sourceforge.net/p/npppythonscript/discussion/1199074/thread/b0cc797e/
    
    NOTES:  
     MS Word has the option of changing the case of selected text by pressing Shift+F3 
     The case changes in the order: UPPER CASE, lower case, Title Case
     It was something I was missing in Notepad++ so I wrote the following script to add the change case feature
     Remember to associate this script with Shift+F3 key combination in the Shortcut Mapper
    
    UPDATES:                    _ver_   _description_
     2013-08-11 Abbas           1.0.0   Original release 
     2014-11-16 Abbas           1.1.0   Edited to include changes suggested by Rufus in the comments
     2017-06-05 Dan Padric      1.1.1   Formatting, commentary, add "Sentence case" & error message
    '''
    
    text = editor.getSelText() # Absorb selected text into tag
    
    if text: # PROCESSING TEXT
        # tuples of check and alter functions
        functable = [
                    (lambda s: s.isupper(),             lambda s: s.lower()), # ............ UPPER CASE     -> lower case
                    (lambda s: s.islower(),             lambda s: s[0].upper() 
                                                                    + s[1:].lower()), # .... lower case     -> Sentence case
                    (lambda s: s[0].isupper() 
                                and s[1:].islower(),    lambda s: s.title()), # ............ Sentence case  -> Title Case
                    (lambda s: s.istitle(),             lambda s: s.upper()), # ............ Title Case     -> UPPER CASE
                    (lambda s: True,                    lambda s: s.upper()) # ............. {none}         -> UPPER CASE
                    ]
    
        for check, alter in functable: # Iterate through the list of checking and altering functions
            if check(text): # ........... TEST
                text = alter(text) # .... MODIFY
                break # ................. task complete
    
        start = editor.getSelectionStart()
        end = editor.getSelectionEnd() # ... positioning of current selection
    
        editor.replaceSel(text) # ....... replace text with modified version
    
        editor.setSel(start, end) # ..... reselect text
    
    else: # NO TEXT SELECTED
        action = notepad.messageBox('No selection made', # .. error message
                                    'Text case toggle', 
                                    MESSAGEBOXFLAGS.OK) 
    
     
    Last edit: Dan Padric 2017-06-05
  • David Hansen

    David Hansen - 2017-07-25

    Nice work Dan! I just have one suggestion to make it act more like Word...

    Instead of displaying a messageBox if no selection is made, you could automatically select the current word and apply the modification to that.

        # Select the "word" at current cursor position
        pos   = editor.getCurrentPos() 
        begin = editor.wordStartPosition(pos,True)
        end   = editor.wordEndPosition(pos,True)
        editor.setSel(start, end)
    
        # Transform word case
        text = editor.getSelText()
        text = alter(text)
        editor.replaceSel(text) 
    
     
    • Dan Padric

      Dan Padric - 2017-08-20

      Hi David. A very valid point you are making. Did you test the result with the cursor on whitespace - in the space between two words?

       
  • David Hansen

    David Hansen - 2017-08-24

    Yep. Take the string 'two words' for example. When the cursor is "on" whitespace it could be to the left of the space ('two| ') or to the right of it (' |words'). Eiher way, wordStartPosition() and wordEndPosition() return the begining and end of the "word" the cursor is touching. If you place the cursor between two spaces (e.g. 'two | spaces') then wordStartPosition() == wordEndPosition() == getCurrentPos().

     
  • David Hansen

    David Hansen - 2017-08-24

    Hi Dan, I encountered a little problem when trying to implement my suggestion, i.e. for a single word 's[0].isupper() and s[1:].islower() == s.title()'. So, when cycling through case changes for a single word, it would get stuck in the the sentance/title case and never proceeds to the upper case. I was able to work around this by changing the order of your functable.

    Here is the updated code.

    #Title:      MS Word-style case change (Shift+F3 feature): 
    #            change the case of selected text from upper to lower to title 
    #Creator:    Abbas 
    #Publish:    https://sourceforge.net/p/npppythonscript/discussion/1199074/thread/b0cc797e/
    
    #NOTES:  
    # MS Word has the option of changing the case of selected text by pressing Shift+F3 
    # The case changes in the order: UPPER CASE, lower case, Title Case
    # It was something I was missing in Notepad++ so I wrote the following script to add the change case feature
    # Remember to associate this script with Shift+F3 key combination in the Shortcut Mapper
    
    #UPDATES:                    _ver_   _description_
    # 2013-08-11 Abbas           1.0.0   Original release 
    # 2014-11-16 Abbas           1.1.0   Edited to include changes suggested by Rufus in the comments
    # 2017-06-05 Dan Padric      1.1.1   Formatting, commentary, add "Sentence case" & error message
    # 2017-08-24 David Hansen    1.2.0   Support for changing case of a word without needing to select it first
    
    # tuples of check and alter functions
    functable = [
                (lambda s: s.isupper(),             lambda s: s.lower()), # ............ UPPER CASE     -> lower case
                (lambda s: s.istitle(),             lambda s: s.upper()), # ............ Title Case     -> UPPER CASE
                (lambda s: s.islower(),             lambda s: s[0].upper() 
                                                                + s[1:].lower()), # .... lower case     -> Sentence case
                (lambda s: s[0].isupper() 
                            and s[1:].islower(),    lambda s: s.title()), # ............ Sentence case  -> Title Case
                (lambda s: True,                    lambda s: s.upper()) # ............. {none}         -> UPPER CASE
                ]
    
    text = editor.getSelText() # Absorb selected text into tag
    
    if not text: # then no selection is made
        # select the current word
        pos   = editor.getCurrentPos() 
        start = editor.wordStartPosition(pos,True)
        end   = editor.wordEndPosition(pos,True)
        editor.setSel(start, end)
        text = editor.getSelText()
    
    for check, alter in functable: # Iterate through the list of checking and altering functions
        if check(text): # ........... TEST
            text = alter(text) # .... MODIFY
            break # ................. task complete
    
    start = editor.getSelectionStart()
    end = editor.getSelectionEnd() # ... positioning of current selection
    
    editor.replaceSel(text) # ....... replace text with Modified Version
    
    editor.setSel(start, end) # ..... Reselect Text
    
     
    Last edit: David Hansen 2017-08-24
  • Dan Padric

    Dan Padric - 2017-08-26

    David, thanks for sharing your addition.
    This demonstrates why I like community driven code.
    Talk to you again some time.

     

Log in to post a comment.