Substituting exact letter

  • I need to find and replace a letter, but it needs to be finished, it’s a music chord. Example: G I want to substitute for <b> G </ b>, this is ok, but there are times that can be like this: G / B and if you ask to replace it it will look like this: <b> G </ b> / B. How to differentiate G alone?

  • @Marcos-Liell said:

    How to differentiate G alone?

    It depends a lot on the circumstances. You didn’t give enough data for us to be sure.

    However, based on my understanding of tabulature and other writing of musical chords, you want it to match a G, even if there are more spaces and chords after, but not if it’s a “G over B”, indicated with a slash between.

    Thus, my mental rule becomes, look for a G, followed by 0 or more spaces, as long as there isn’t a slash after that.

    • Thus, my search regex becomes: (G)(\h*)(?![/\h]) – this looks for a G and stores it in memory $1, and stores the 0-or-more spaces in memory $2, and makes sure that the character after the 0-or-more-spaces is not a / (and also not a space, because otherwise, it just makes the \h* shorter), but doesn’t store or gobble that character.
    • and my replace is <b> $1 </b>$2 – this replaces the match with your bold markup (I assume that’s what it is) around the matched G chord, followed by whatever spaces used to be there.
    • mode is regular expression, of course.

    I made it easy to customize: if you want to change the chord you are searching for (like a Bb chord or F# chord), just change the G to something else; everything else in the regex is generic.

    With the example data:

    G   C   G   D   G   G
    G / B   C   G   D   G/B G

    it becomes

    <b> G </b>   C   <b> G </b>   D   <b> G </b>   <b> G </b>
    G / B   C   <b> G </b>   D   G/B <b> G </b>

    Based on your description, I think it’s what you want… but I could be wrong. If that’s not correct, please be more explicit, giving examples of when to change and when not to change, showing before and after examples

    FYI: I often add this to my response in regex threads, unless I am sure the original poster has seen it before. Here is some helpful information for finding out more about regular expressions, and for formatting posts in this forum (especially quoting data) so that we can fully understand what you’re trying to ask:

    This forum is formatted using Markdown, with a help link buried on the little grey ? in the COMPOSE window/pane when writing your post. For more about how to use Markdown in this forum, please see @Scott-Sumner’s post in the “how to markdown code on this forum” topic, and my updates near the end. It is very important that you use these formatting tips – using single backtick marks around small snippets, and using code-quoting for pasting multiple lines from your example data files – because otherwise, the forum will change normal quotes ("") to curly “smart” quotes (“”), will change hyphens to dashes, will sometimes hide asterisks (or if your text is c:\folder\*.txt, it will show up as c:\folder*.txt, missing the backslash). If you want to clearly communicate your text data to us, you need to properly format it.

    If you have further search-and-replace (“matching”, “marking”, “bookmarking”, regular expression, “regex”) needs, study this FAQ and the documentation it points to. Before asking a new regex question, understand that for future requests, many of us will expect you to show what data you have (exactly), what data you want (exactly), what regex you already tried (to show that you’re showing effort), why you thought that regex would work (to prove it wasn’t just something randomly typed), and what data you’re getting with an explanation of why that result is wrong. When you show that effort, you’ll see us bend over backward to get things working for you. If you need help formatting, see the paragraph above.

    Please note that for all regex and related queries, it is best if you are explicit about what needs to match, and what shouldn’t match, and have multiple examples of both in your example dataset. Often, what shouldn’t match helps define the regular expression as much or more than what should match.

  • @PeterJones said:


    Thank you very much, it worked. And to validate when the next character is a letter? Ex: Cords, I do not want you to be <b> C </ b> ords

    Thank you.

  • @Marcos-Liell said:

    And to validate when the next character is a letter

    So I would modify my textual description of the rules, using C as the example this time instead of G: “Find a C, not followed by an alphanumeric, followed by any number of spaces (including zero), not followed by a slash or space.”

    The regex just needs to be modified to exclude (but not capture or gobble) a “word character” (basically, alphanumeric) when looking for the C, using (?!\w)… which means the final Find what = (C(?!\w))(\h*)(?![/\h]). The replacement stays the same

    With the new example text:

    C   G   D   C   C
    C / E Chord C  Cm C

    it would transform to

    <b> C </b>   G   D   <b> C </b>   <b> C </b>
    C / E Chord <b> C </b>  Cm <b> C </b>

    If you have any more tweaks you’d like, please try reading some of the docs from the regex FAQ linked above, especially here. After reading that, try to make the modification yourself. If you cannot get it to work yourself, then show us how you modified the regex, and explain what you think it should be doing, and show us what it really does.

  • @PeterJones said:


    Thankyou Very Much

  • Hello @marcos-liell, @PeterJones and All,

    Here is a second search regex which contains two consecutive structures : a negative  look-ahead, followed with a positive  look-ahead, containing, itself, a nested negative  look-ahead !

    So, this regex only searches for the upper-case C letter, but ONLY IF :

    • Not followed by a word character


    • Followed with any range, even null, of horizontal blank characters

      • But ONLY IF  that range is not followed, itself, by a / symbol

    Note the interesting use of the possessive quantifier *+, after \h. As no backtracking process may occur, we’re sure that, after the blank characters matched zone, there will be, necessarily, a non blank character ;-))

    As we just grab the C character, we can use the $0 syntax, which, simply, represents… … the C letter !

    Hence, the regex S/R, below :

    SEARCH (?-i)C(?!\w)(?=\h*+(?!/))

    REPLACE <b> $0 </b>

    Which gives the same result :

    <b> C </b>   G   D   <b> C </b>   <b> C </b>
    C / E Chord <b> C </b>  Cm <b> C </b>

    Best Regards,


  • Thank you very much, it helped me a lot.

    Another question, is there any plugin that can do this?

    I would like to select with the Mouse the letter C, to press a button of atralho and to insert with this command the Tags in C?

    Example: I select Letter C, press Crtl + 9 and insert as follows: <b> C </ b>

    Thank you

  • @Marcos-Liell

    I don’t know about a plugin…maybe. Maybe it is something NppExec plugin can do easily (experts on that could chime in…).

    For myself, I turn to scripting for such things. Example: Create a short Pythonscript and bind it to the ctrl+9 key: editor.replaceSel('<b>' + editor.getSelText() + '</b>')

  • Hi, @marcos-liell, @PeterJones and All

    May be, it’s worth to point out that the regex engine working position, does NOT change, when evaluating any look-around structure ! So, regarding my regex version, this working location is :

    • Between the upper-case C and its next character, when evaluating the negative look-ahead (?!\w)

    • Still, between the upper-case C and its next character, when evaluating the positive look-ahead (?=\h*+.....)

    • And still, between the upper-case C and its next character, when evaluating the nested negative look-ahead (?=....(?!/)

    For instance, if we consider the following regex :


    It would match, for instance, the string “C #” ( with 2 space chars between C and #). This means that, when the regex engine is about to evaluate the ending part of the regex \x20\x20#, its working location is, as expected, right after the C letter !

    Now, after reflection and some tests, I thought about an other solution, using just 1 positive look-ahead :

    SEARCH  :  (?x-i)  C  (?=  \h++[^/]  |  [^\w\h/]  )
    REPLACE :  <b> $0 </b>   

    Note that I used the free-spacing regex mode, (?x), in order to easily see the main parts of the regex ;-))

    So, the regex engine searches for an upper-case C ONLY IF , right after, there is :

    • A non-null range of horizontal blank characters, followed with a char, different from the / symbol ( => it can be an EOL char ! )


    • A NON-word character, different from, both, an horizontal blank char and the / symbol



Log in to reply