60

Every once in a while I want to replace all instances of values like:

<BarFoo>

with

<barfoo>

i.e. do a regular expression replace of all things inside angle brackets with its lowercase equivalent.

Anyone got a nice snippet of Lisp that does this? It's safe to assume that we're dealing with just ASCII values. Bonus points for anything that is generic enough to take a full regular expression, and doesn't just handle the angle brackets example. Even more bonus points to an answer which just uses M-x query-replace-regexp.

Thanks,

Dom

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212

3 Answers3

98

Try M-x query-replace-regexp with "<\([^>]+\)>" as the search string and "<\,(downcase \1)>" as the replacement.

This should work for Emacs 22 and later, see this Steve Yegge blog post for more details on how Lisp expressions can be used in the replacement string.

For earlier versions of Emacs you could try something like this:

(defun tags-to-lower-case ()
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "<[^>]+>" nil t)
      (replace-match (downcase (match-string 0)) t))))
Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
  • 10
    That's cool! I wasn't aware of \,() in Emacs regular expressions. – emk Mar 24 '09 at 11:40
  • 1
    This gets me the error "Invalid use of `\' in replacement text" – Dominic Rodger Mar 24 '09 at 11:46
  • 1
    Regexp should be "<\\([^>]+\\)>" and the replacement doesn't work as expected if the search string matches tag in all caps. – Eugene Morozov Mar 24 '09 at 12:02
  • I've edited the answer so that the backslashes in the search expression are now visible. – Luke Girvin Mar 24 '09 at 12:21
  • Ah - that's probably why it didn't work, I'm running Emacs 21.2.1 - any other ideas? – Dominic Rodger Mar 24 '09 at 12:45
  • 6
    Emacs can handle .*? as a non-greedy match. – ashawley Mar 24 '09 at 18:52
  • 1
    Re: This gets me the error "Invalid use of `\' in replacement text" - if you are editing a previous command via redo (M-x esc esc), you'll get this, because the M-x query-replace-regexp command appears to replace \,() with the actual lisp expression. If you run M-x query-replace-regexp, you can use \,() in the replacement expression. – Avi Tevet Nov 16 '15 at 17:52
  • @emk Indeed! It's not even mentioned on the [Emacs regexp wiki page](https://www.emacswiki.org/emacs/RegularExpression)! – Geremia Aug 08 '16 at 16:32
  • Nice! @LukeGirvin is it possible to use this is in a multibuffer workflow? I was able to use it for a single buffer but trying to use 'U' for multibuffers in IBuffer mode resulted in the dreaded "Invalid use of `\' in replacement text" -- I tried various escaping to no avail. – jstevenco Feb 08 '19 at 23:39
  • I just used this and it works. But, I wonder why the `\,` construct. Does it have a precedence from elsewhere? – grdvnl Apr 08 '21 at 21:55
0

I realize this question is ancient, but I just discovered how to do this in Emacs before version 22 (my version is 21.3.1) without the need for defining a custom Lisp function: use M-x query-replace-regexp-eval (mentioned at the top of this Emacs wiki page) with <\([^>]+\)> as the search string and (concat "<" (downcase \1) ">") as the replacement.

This should work with any replacement string that can be defined as a concatenation of parts, including captured groups not modified by any function. For example:

<BarFoo baz="Quux">

can have just the tag name downcased:

<barfoo baz="Quux">

by using search string <\([A-Za-z]+\)\([^>]*\)> and replacement (concat "<" (downcase \1) \2 ">") (which also works on OP's example that looks like a tag with no attributes).

JustPlainMJS
  • 1,583
  • 1
  • 11
  • 6
0

When using evil, you can simply do :%s/<\([^>]+\)>/<\L\1>

\L is responsible for lowercasing all following letters, this should also work for query-replace-regexp.

I have not found documentation around Emacs for that, but it seems to match this list: https://www.boost.org/doc/libs/1_44_0/libs/regex/doc/html/boost_regex/format/perl_format.html

xeruf
  • 2,602
  • 1
  • 25
  • 48