0

I have a regexp that finds and highlights operators in C++ but I can't for the life of me work out how to match operator[] using regexp. The usual trick of escaping the characters doesn't seem to work, it merely ends matching.

    (font-lock-add-keywords
     nil '(
       ;; operators
       ("[~^&\|!<>:=,.\\+*/%-]" . font-lock-keyword-face) ))

My second (incomplete) attempt using regexp-builder and moving escaped symbols to the end of the match got me the opening brace:

    ("[~^=<>&/.,\[\|\*\+\-]" . font-lock-keyword-face)

but adding \] or moving \[ kills any matching. What am I missing?

Fatlimey
  • 53
  • 1
  • 5

3 Answers3

3

I use regexp-opt for this, because it's much more readable. Relevant config:

(setq operators-font-lock-spec
      (cons (regexp-opt '("+" "-" "*" "/" "%" "!"
                          "&" "^" "~" "|"
                          "=" "<" ">"
                          "." "," ";" ":" "?"))
            (list
             0 ;; use whole match
             'font-lock-builtin-face
             'keep ;; OVERRIDE
             )))

(setq brackets-font-lock-spec
      (cons (regexp-opt '("(" ")" "[" "]" "{" "}"))
            (list
             0 ;; use whole match
             'font-lock-bracket-face
             'keep ;; OVERRIDE
             )))

(font-lock-add-keywords
 'c++-mode
 (list
  operators-font-lock-spec
  brackets-font-lock-spec
  (cons c-types-regexp 'font-lock-type-face)))

brackets-font-lock-spec is separate because I use a different face for them.

jpkotta
  • 9,237
  • 3
  • 29
  • 34
2

To match a literal ], put it right after the opening [:

"[]~^=<>&/.,\[\|\*\+\-]"

Since an empty character choice wouldn't make any sense in a regexp, this combination is given the alternative interpretation of matching an actual ].

legoscia
  • 39,593
  • 22
  • 116
  • 167
2

You need two consecutive backslashes to escape a character for a regular expression in a literal string, i.e.

"[]~^&|!<>:=,.+\\[*/%-]"

A single backslash is interpreted by the Emacs Lisp reader when parsing the string literal, and denotes escape sequences, e.g. \n for a newline character. If the backslash doesn't start a known escape sequence as in this case (\[ is no special character), the backslash is simply dropped. In this case, a single [ ends up in the resulting string, which creates an invalid regular expression and thus prevents it from matching.

  • Suggest adding the first `]` as in @legoscia's answer, as the current regex won't match the close bracket otherwise. Also, unless I'm mistaken, you can unescape the `+`, as it will be treated as a literal inside square brackets. – Dan Aug 07 '14 at 16:54
  • @Dan Thanks, I updated my answer accordingly. I didn't really look at the contents of the expression, I just noticed and fix the flawed escaping. I should have read the question more carefully. –  Aug 07 '14 at 17:03
  • Part of my problem is that `re-builder` only displays the first 200 matches. Removing the `\\ ==============` style comments got me further and showed that you were correct. Thanks all! – Fatlimey Aug 07 '14 at 19:16