2

I am looking for an elisp function that accepts a string and returns the same in title case (i.e., all words capitalized, except for "a", "an", "on", "the", etc.).

I found this script, which requires a marked region.

Only, I need a function that accepts a string variable, so I can use it with replace-regex. I would love to see a version of the above script that can accept either or...

Drew
  • 29,895
  • 7
  • 74
  • 104
Adam
  • 2,137
  • 16
  • 29

3 Answers3

3

Something like this?

(progn
  (defun title-case (input) ""
         (let* (
                (words (split-string input))
                (first (pop words))
                (last (car(last words)))
                (do-not-capitalize '("the" "of" "from" "and" "yet"))) ; etc
           (concat (capitalize first)
                   " "
                   (mapconcat (lambda (w)
                                (if (not(member (downcase w) do-not-capitalize))
                                    (capitalize w)(downcase w)))
                              (butlast words) " ")
                   " " (capitalize last))))
  (title-case "the presentation of this HEADING OF my own from my keyboard and yet\n"))
choroba
  • 231,213
  • 25
  • 204
  • 289
  • Hey @choraba, thank you for posting this! The script works great for a single string variable. But I found that it errors when used with `replace-regex`. This is the message I get `helm-M-x: Error evaluating replacement expression: (wrong-type-argument char-or-string-p nil)`... For completeness, it may also be useful to give the option to use this function on a highlighted region, similar to this http://ergoemacs.org/emacs/elisp_command_working_on_string_or_region.html – Adam Jul 18 '18 at 08:43
1

I'd say that the script you linked to does a good job at title casing. You can use it as-is.

That leaves us with two more questions:

  • How can we make it accept a string?
  • How can we write a function which accepts both a string or a (marked) region?

Working with strings in Emacs is idiomatically done in temporary buffers which are not displayed. You could write a wrapper like this:

(defun title-capitalization-string (s)
  (with-temp-buffer
    (erase-buffer)
    (insert s)
    (title-capitalization (point-min)
                          (point-max))
    (buffer-substring-no-properties (point-min)
                                    (point-max))))

Now, for a function which magically does what you mean, consider something like this:

(defun title-capitalization-dwim (&optional arg)
  (interactive)
  (cond
   (arg
    (title-capitalization-string arg))
   ((use-region-p)
    (title-capitalization-string
     (buffer-substring-no-properties (region-beginning)
                                     (region-end))))
   (t
    (title-capitalization-string
     (buffer-substring-no-properties (point-at-bol)
                                     (point-at-eol))))))

It accepts an optional argument, or an active region or falls back to the text on the current line. Note that this function is not really useful when used interactively, because it doesn't show any effects. Hat tip also to https://www.emacswiki.org/emacs/titlecase.el

License

I put all this code under the Apache License 2.0 and the GPL 2.0 (or later at your option) in addition to the site's default license.

Stefan Kamphausen
  • 1,615
  • 15
  • 20
1

Use M-x

upcase-initials-region is an interactive built-in function in ‘C source code’.

(upcase-initials-region BEG END)

Upcase the initial of each word in the region. This means that each word’s first character is converted to either title case or upper case, and the rest are left unchanged. In programs, give two arguments, the starting and ending character positions to operate on.

Geremia
  • 4,745
  • 37
  • 43