Emacs Lisp Example: title-case-string-region-or-line

Perm URL with updates: http://xahlee.org/emacs/elisp_title_case_text.html

This page shows you how to write a emacs lisp command to change letter case by title convention.

In English writing, the title follows a particular convention of capitalization. For example, it should be “A Tale of Two Cities”, not “A Tale Of Two Cities”.

I think this is rather a silly convention. For a while, i experimented by simply following a logically simpler style, of capitalizing the first letter of all words. (➲ The Writing Style on XahLee.org) But after a while, i find it rather jarring.

Part of the reason is that it's new, thus it will get some used to. This i expected. However, the other thing that turns out is that, the capitalization has subtle function for emphasis. For example, “Kung Fu versus Karate” seems better than “Kung Fu Versus Karate”.

It's rather cumbersome to manually capitalize words following this convention. So, i wrote a emacs command. Here's the code:

(defun title-case-string-region-or-line (ξstring &optional ξregion-boundary)
  "Capitalize the current line or text selection, following title conventions.

Capitalize first letter of each word, except words like {to, of,
the, a, in, or, and, …}. If a word already contains cap letters
such as HTTP, URL, they are left as is.

When called in a elisp program, if ξREGION-BOUNDARY is nil,
returns the changed ξSTRING, else, work on the region.
ξREGION-BOUNDARY is a pair [from to], it can be a vector or
list."
  (interactive
   (let ((bds (get-selection-or-unit 'line)))
     (list nil (vector (elt bds 1) (elt bds 2)) ) ) )

  (let ( replacePairs
         (workOnStringP (if ξregion-boundary nil t ) )
         (p1 (elt ξregion-boundary 0))
         (p2 (elt ξregion-boundary 1))
         )

    (setq replacePairs '(
                         [" A " " a "]
                         [" And " " and "]
                         [" At " " at "]
                         [" As " " as "]
                         [" By " " by "]
                         [" Be " " be "]
                         [" Into " " into "]
                         [" In " " in "]
                         [" Is " " is "]
                         [" It " " it "]
                         [" For " " for "]
                         [" Of " " of "]
                         [" Or " " or "]
                         [" On " " on "]
                         [" The " " the "]
                         [" That " " that "]
                         [" To " " to "]
                         [" Vs " " vs "]
                         [" With " " with "]
                         [" From " " from "]
                         ))

    (let ((case-fold-search nil))
      (if workOnStringP
          (progn
            (replace-pairs-in-string-recursive (upcase-initials ξstring) replacePairs)
            )
        (progn
          (save-restriction
            (narrow-to-region p1 p2)
            (upcase-initials-region (point-min) (point-max) )
            (replace-regexp-pairs-region (point-min) (point-max) replacePairs t t)
            ) ) ) ) ) )

I used some elisp utils i wrote. You'll need to get it at: code.google.com xeu_elisp_util.el. This command is also bundled there.

Popular posts from this blog

Browser User Agent Strings 2012

11 Years of Writing About Emacs

does md5 creates more randomness?