2

I have several lists with regexp matching categories of file extensions:

(let* (
    (txt-regexp '("txt" "md" "log" "org" "conf" "rtf"))
    (el-regexp '("el" "lisp"))
    (tex-regexp '("tex"))
    (pdf-regexp '("pdf"))
    (image-regexp '("tif" "bmp" "jpg" "png" "gif"))))

I would like to match only extensions with word boundaries -- e.g., \\btxt\\b for file extensions ending in txt. However, I would like to avoid writing every file extension with \\bname-of-extension\\b. An example of how to convert each category of lists into extensions with word boundaries would be great:

Example:

  • (txt-regexp '("txt" "md" "log" "org" "conf" "rtf"))

would be converted into

  • (txt-regexp-modified '("\\btxt\\b" "\\bmd\\b" "\\blog\\b" "\\borg\\b" "\\bconf\\b" "\\brtf\\b"))
  • Would a function transforming ("txt" "md" "log" "org" "conf" "rtf") (and similar) to ("\\btxt\\b" "\\bmd\\b" "\\blog\\b" "\\borg\\b" "\\bconf\\b" "\\brtf\\b") do the job? – Constantine Nov 3 '14 at 20:10
  • @Constantine -- yes, thank you. Both of the initial solutions (i.e., by shosti and glucas) work well. There's some ongoing edits by the authors, so I'll check back later on today to try out the final versions. – lawlist Nov 3 '14 at 20:44
  • If you're going to build a regexp to recognize any of these strings, see regexp-opt. – Gilles Nov 11 '14 at 0:18
4

You can use rx-to-string to build a regular expression form and convert it to a string:

(setq txt-regexp-modified 
    (mapcar (lambda (elt) 
            (rx-to-string `(sequence word-boundary ,elt word-boundary) t))
         txt-regexp))

In this case the regular expression you want is simple enough you could do this with string concat, but the rx functions are handy when you are building more complicated expressions.

4

Converting the strings to include boundaries is easy using standard Elisp functions:

(defun my-boundaryize (regexp)
  (concat "\\b" regexp "\\b"))

(let ((txt-regexp-modified (mapcar #'my-boundaryize txt-regexp)))
  ...)

If you're feeling fancy, you could use a macro to make this automatic:

(defun my-convert-to-boundaryized (var-val) ;; Converts a single (var val) pair in the let clause
  (let ((var (car var-val))
        (val (cadr var-val)))
    (list (intern (concat (symbol-name var) "-modified")) ;; changes the let variable by appending "-modified"
          `(mapcar #'my-boundaryize ,val)))) ;; maps my-boundaryize over the let value

(defmacro let-boundaryized (vars-vals &rest body)
  (let ((let-clauses (mapcar #'my-convert-to-boundaryized vars-vals)))
    `(let ,let-clauses
       ,@body)))

(let-boundaryized ((txt-regexp '("txt" "org"))
                   (el-regexp '("el" "lisp")))
  txt-regexp-modified) ; => '("\\btxt\\b" "\\borg\\b")

This is almost certainly overkill for this particular problem (and not particularly good macro style since it introduces magical variable names); I'm including it as an example of how you might use macros to solve this general type of problem.

  • Consider fixing paren matching: (let ((txt-regexp-modified (mapcar #'my-boundaryize txt-regexp))) ...). (SE would not let me submit this edit: too small.) – Constantine Nov 3 '14 at 20:26
  • This answer works well, but I could only choose one correct answer -- thank you for teaching me new concepts -- greatly appreciated! – lawlist Nov 3 '14 at 21:13
2

For a simple list, a mapcar would return the modified list you want:

(setq txt-regexp '("txt" "md" "log" "org" "conf" "rtf"))
(mapcar #'(lambda (x) (concat "\\b" x "\\b")) txt-regexp)

Not sure about the use-case without context in your let* binding, but if, instead, you had a list of lists, you could wrap the mapcar in a dolist:

(let ((re '((txt-regexp   ("txt" "md" "log" "org" "conf" "rtf"))
            (el-regexp    ("el" "lisp"))
            (tex-regexp   ("tex"))
            (pdf-regexp   ("pdf"))
            (image-regexp ("tif" "bmp" "jpg" "png" "gif")))))
  (let (bounded)
    (cl-dolist (i re (nreverse bounded))
      (push (mapcar #'(lambda (x) (concat "\\b" x "\\b")) (cadr i)) bounded))))
  • This answer works well, but I could only choose one correct answer -- thank you for teaching me new concepts -- greatly appreciated! – lawlist Nov 3 '14 at 21:14

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.