I write regex for font-lock and I know that the date should appear in first 40 chars of line.

How can I limit search beyond some limit?

I tried to add ^.\\{0,40\\}XXX but Emacs regex . is greedy and regex requires non-trivial rewriting to workaround greediness.

UPDATE I'm using font-lock-add-keywords

UPDATE @Stefan I have regex that skip optional date part, the only time part is required. With prefix .\\{0,40\\} date part is ignored (not highlighted). I can't use [^-] or [^-[:digit:]] because it is for log files and I don't know prefix in advance.

My goal is to limit regex trying to parse long lines.

UPDATE 3 My regex:

(defvar log4-hi-time-keywords
  '(("^.\\{0,40\\}\\(\\(:?[0-9]\\{2\\}?[0-9]\\{2\\}.[0-9]\\{2\\}.[0-9]\\{2\\}.\\|\\<\\)[0-9]?[0-9]:[0-9][0-9]:[0-9][0-9]\\>\\(:?\\.[0-9]\\{3\\}\\)?\\)" 1 'log4-hi-time-face))
  "Highlight regex for partial ISO date.")

(font-lock-add-keywords nil log4-hi-time-keywords)

With addition of ^.\\{0,40\\} only time part of 2020-02-23 13:39:03.215 is highlighted.

I hope regex isn't that scary.

  • 1
    Please say what did not behave as you intended when you tried ^.\\{0,40\\}XXX. – Stefan Feb 24 at 14:05
  • @Stefan Please check update 2. – gavenkoa Feb 24 at 14:14
  • 1
    Without seeing the rest of the regexp I can't begin to guess why "date part is ignored" (and I don't event know what that date part is supposed to look like nor what the rest looks like either). – Stefan Feb 24 at 14:25
  • 1
    How can . be greedy? It can only match a single non-newline character. Only repetition operators can be greedy, i.e. *, +, and ?. – Basil Feb 24 at 15:03
  • @all I added regex and matching string. @Basil you are right about greediness. I meant .\{0,40\} all the time. – gavenkoa Feb 24 at 16:33

I think this is a job for a function in font-lock. It looks like your regular expression matches 0-40 characters, then a date, which does not sound like what you want at all. You want a date in the first 40 characters.

Here is a partial solution that matches dates like 2020-02-26 in the first 40 characters. If the date match goes outside the 40 chars, then it just searches again. This is lightly tested and seems to do what you want. You can replace the regexp with your more complex one, and the desired face.

(defun date-match (limit)
  "Match date in the first 40 chars."
  (when (re-search-forward "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)" limit t)
    (if (> (current-column) 39)
    ;; date is past 40 char, so search again
    (date-match limit)
      ;; return non-nil so it continues

 '((date-match 0 font-lock-warning-face)))
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.