2

I would like to match all filenames with only one dot in them:

(re-search-forward "[a-z0-9A-Z]?+\\.dsp$")

bdsp
plop.dsp.zzz
plop.1.dsp
plop.dsp

Here, the regexp matches plop.1.dsp, but it should ignore that and match nothing but the last line, plop.dsp.

Any Elisp regexp gurus around to enlighten me?

2 Answers 2

4

You could use M-x re-builder to construct your regexp visually.

To match the stuff described in your question, you just have to add ^ at the beginning of your regex. Then it starts at the beginning of the line.

(re-search-forward "^[a-z0-9A-Z]?+\\.dsp$")
4

Different filesystems impose different restrictions on filenames. If the only condition you care about is the presence of exactly one dot with at least one other character before and after the dot, the correct regular expression is

"\\`[^.]+\\.[^.]+\\'"

If you also want the file extension to be dsp, then you can use

"\\`[^.]+\\.dsp\\'"

Using your sample filenames:

(mapcar (lambda (filename)
          (list filename (string-match-p "\\`[^.]+\\.dsp\\'" filename)))
        '("bdsp"
          "plop.dsp.zzz"
          "plop.1.dsp"
          "plop.dsp"))

  ;; => (("bdsp" nil)
  ;;     ("plop.dsp.zzz" nil)
  ;;     ("plop.1.dsp" nil)
  ;;     ("plop.dsp" 0))

If you prefer, you can also construct these regexps using the rx macro:

(rx bos (+ (not (in ?.))) ?. (+ (not (in ?.))) eos)
  ;; => "\\`[^.]+\\.[^.]+\\'"
(rx bos (+ (not (in ?.))) ".dsp" eos)
  ;; => "\\`[^.]+\\.dsp\\'"

Note:

  1. When matching buffer lines, e.g. using re-search-forward, you should anchor your regexp with

    ^ and $
    

    to denote the beginning and end of each line, respectively. When matching filename strings as per my examples, however, it is instead better to use

    \\` and \\'
    

    to denote the beginning and end of the string, respectively. This protects you from the theoretical possibility of matching filenames containing newline characters.

  2. In order for the single dot restriction to work for an arbitrary filename, the regular expression must be matched against the non-directory part of the given filename, e.g.

    (string-match-p "\\`[^.]+\\.dsp\\'" "~/foo.bar/baz.dsp")
      ;; => nil
    (string-match-p "\\`[^.]+\\.dsp\\'" (file-name-nondirectory "~/foo.bar/baz.dsp"))
      ;; => 0
    
3
  • You example returned eval: Search failed: "\`[^.]+\\.dsp\\'" but I upvoted you anyway for your thorough and quick answer :)
    – yPhil
    Jul 17, 2017 at 16:01
  • @yassinphilip How are you using that regexp? In a buffer with re-search-forward or against a string with string-match/string-match-p/replace-regexp-in-string etc.? In the former case you should use the ^ and $ anchors. In the latter case there should be two backslashes before the backtick at the start of the regexp.
    – Basil
    Jul 17, 2017 at 16:15
  • @yassinphilip To clarify, in a buffer containing the filenames you list, this should work: (re-search-forward "^[^.]+\\.dsp$"). Unless I'm missing something, that is.
    – Basil
    Jul 17, 2017 at 16:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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