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:
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.
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