Whats the correct way to match a filename from a full path using string-match-p.

Say I want to check if the file is a git commit message COMMIT_EDITMSG or svn-commit.tmp or svn-commit.3.tmp to pass to 3rd party code that only takes regular expressions (something like auto-mode-alist).

eg: (string-match my-clever-regex "/path/to/svn-commit.3.tmp")

Using the COMMIT_EDITMSG as an example:


How can I match a filename which may or may not contain a path?

  • Match how/where? Isearch? grep, re-search-forward? Emacs regexp or regexp for find or something else? Define "correct". Please clarify what you're trying to do. – Drew Jan 28 '20 at 1:36
  • 1
    Emacs lisp provides specific functions to extract parts of filenames: no regex needed. – NickD Jan 28 '20 at 4:31
  • 1
    If you're matching buffer-file-name, that will have a directory component to it, in which case "/COMMIT_EDITMSG\\'" may be all you need for a regexp. – phils Jan 28 '20 at 6:37
  • 1
    I don't know whether it could be \ on WIN32 because I've no idea where this value is coming from; but if it's coming from Emacs then you may find that it's / even on WIN32. I suggest either testing this yourself, or else giving details so that someone else would be able to do so. – phils Jan 28 '20 at 8:07
  • 3
    \' because that's the correct way to say "end of text". Whilst not recommended, newlines are valid in filenames on most systems, so $ is potentially insufficient. For more examples see virtually every entry in auto-mode-alist. – phils Jan 28 '20 at 8:12

I'd do

       (file-name-nondirectory <file>))
  • 1
    This question asked about using regular expressions which is significant, I've updated my question to explain why I can't use some elisp to check the string. – ideasman42 Jan 28 '20 at 14:44

This regular expression matches both COMMIT_EDITMSG and /path/to/COMMIT_EDITMSG.

(string-match-p "\\`\\(?:.*[\\/]\\)?COMMIT_EDITMSG\\'" "/path/to/COMMIT_EDITMSG")

If the filename is from buffer-file-name there is no need to check for \ separators as Emacs converts them to /, there is also no need to account for no need to account for only the filename case as the filename will either be the full path or ./.

Since this isn't part of the original question, adding this as a second example.

(string-match-p "/COMMIT_EDITMSG\\'" "/path/to/COMMIT_EDITMSG")

Thanks to suggestions from @phils which helped improve this answer.

  • 1
    \\(\\|foo\\) is a bit simpler as \\(foo\\)?. – phils Jan 28 '20 at 6:16
  • 1
    Where are you receiving paths with backslash separators from? AFAIK it's uncommon to have to deal with DOS separators explicitly -- see (elisp)File Names – phils Jan 28 '20 at 6:16
  • 2
    Assuming you don't need to capture that sub-group, I'd suggest "\\(?:\\`\\|[\\/]\\)COMMIT_EDITMSG\\'" (n.b. newlines are valid in filenames). And if you don't need to support backslashes then just / instead of [\\/] of course. And maybe go with string-match-p if you aren't capturing anything. – phils Jan 28 '20 at 6:20
  • The filenames are from buffer-file-name, which might be called on a windows system. – ideasman42 Jan 28 '20 at 15:13
  • 1
    In which case I believe you can forget about \ as Emacs stores file names using / internally so that elisp programs work consistently across systems. The aforementioned note in (elisp)File Names will certainly be applicable to buffer-file-name. – phils Jan 28 '20 at 20:30

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.