emacs/var/elfeed/db/data/a8/a8272751619566f2f5cdb353b226bae7231689bc
2022-01-03 12:49:32 -06:00

85 lines
3.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p>Earlier today I wanted to convert a bunch of Org meta data keywords to
lower case notation, with the help of <code>isearch-forward-regexp</code> and
<code>query-replace-regexp</code>. This included everything from special comments,
like <code>#+TITLE:</code> to property drawers in the form of <code>:PROPERTIES:</code>.
There were 340 such cases in my file and I was reluctant to do so
manually. Thankfully, Emacs makes such a task fairly simple once you
get past the essentials, because it lets you evaluate arbitrary Elisp
forms for the replacement text. This includes the possibility of
running some function on a matched regexp group. In this case that
function was <code>(downcase OBJECT)</code>.</p>
<p>First I needed a regular expression that would capture all targets.
<code>isearch-forward-regexp</code> and its <code>query-replace-regexp</code> counterpart
expect a single backslash for the escape character, so I ended up with
this pattern:</p>
<pre><code>^\(#\|:\)[^ ].*?:
</code></pre>
<p>If I were to test this in the buffer, I could use <code>M-x re-builder</code>,
which however requires double backslashes (same for when you write Elisp
code):</p>
<pre><code>^\\(#\\|:\\)[^ ].*?:
</code></pre>
<ul>
<li>
<p>Once I was sure of the regular expression I had to use, I went to the
top of the buffer and invoked <code>isearch-forward-regexp</code> (bound to
<code>C-M-s</code> by default).</p>
</li>
<li>
<p>Entered the pattern <code>^\(#\|:\)[^ ].*?:</code>, got live feedback of the
matching items, and switched to <code>query-replace</code> with <code>C-%</code>
(<code>isearch-query-replace</code>). When the Isearch is regexp-aware so is the
corresponding <code>query-replace</code>.</p>
</li>
<li>
<p>For the replacement text I instructed the command to evaluate the
<code>downcase</code> function. This is done by escaping the comma operator
(<code>,</code>) and then supplying the function with a regexp group. Because I
wished to match everything, the group should be <code>\0</code>. Which means
that the replacement should be expressed thus: <code>\,(downcase \0)</code>.</p>
</li>
</ul>
<p>Try this with any string in a buffer, say, <code>Hello</code>:</p>
<ul>
<li><code>M-x query-replace-regexp</code></li>
<li><code>Hello</code></li>
<li><code>\,(upcase \0)</code></li>
</ul>
<p>Confirm the operation and you should get <code>HELLO</code>. This works with
multiple groups and can read a series of Elisp forms. An example with
<code>Hello world</code>:</p>
<ul>
<li><code>M-x query-replace-regexp</code></li>
<li><code>\(Hello\) \(world\)</code></li>
<li><code>\,(downcase \1) \,(capitalize \2)</code></li>
</ul>
<p>Which should give you <code>hello World</code>.</p>
<p>The elegant minimalism of the <code>query-replace</code> interface grants you the
power to either replace each match one at a time or hit the exclamation
mark (<code>!</code>) to answer “yes to all”. This is what I did to downcase all
340 matches. Voila! All of my Org files meta data were converted to
lower case in one go.</p>
<p>Finally, I discovered <code>query-replace-regexp-eval</code> which saves you from
adding the escaped comma operator for the replacements Elisp form.
However its doc string reads thus:</p>
<pre><code>Interactive use of this function is deprecated in favor of the
\, feature of query-replace-regexp. For non-interactive use, a loop
using search-forward-regexp and replace-match is preferred.
</code></pre>