Capitalizes words according to typical English titling conventions

Hi All,

I'm still a total noob at scripting so am pretty hopeless when knowing exactly what I need to do to make this work. I know Keyboard Maestro should be able to do this... But working out how to execute this script is still beyond me.

The Source of this script is from the PopClip Title Case Extension here which uses U.K. titling conventions.

What I'd like to achieve, is to select a number of files in Finder or any Application that I wish to convert to Title Case (using this perl script) and have Keyboard Maestro triggered with a shortcut to rename all those files via a script action.

Any help with this would be greatly appreciated! Thank you for your help in advance. :grinning:

Perl Script:

#!/usr/bin/perl

# 	This filter changes all words to Title Caps, and attempts to be clever
#	about *un*capitalizing small words like a/an/the in the input.
#
#	The list of "small words" which are not capped comes from
#	the New York Times Manual of Style, plus 'vs' and 'v'. 
#
#	10 May 2008
#	Original version by John Gruber:
#	http://daringfireball.net/2008/05/title_case
#
#	28 July 2008
#	Re-written and much improved by Aristotle Pagaltzis:
#	http://plasmasturm.org/code/titlecase/
#
#   Full change log at __END__.
#
#	License: http://www.opensource.org/licenses/mit-license.php
#


use strict;
use warnings;
use utf8;
use open qw( :encoding(UTF-8) :std );


my @small_words = qw( (?<!q&)a an and as at(?!&t) but by en for if in of on or the to v[.]? via vs[.]? );
my $small_re = join '|', @small_words;

my $apos = qr/ (?: ['’] [[:lower:]]* )? /x;

while ( <> ) {
	#s{\A\s+}{}, s{\s+\z}{};

	$_ = lc $_ if not /[[:lower:]]/;

	s{
		\b (_*) (?:
			( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ |   # file path or
			  [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos )  # URL, domain, or email
			|
			( (?i: $small_re ) $apos )                         # or small word (case-insensitive)
			|
			( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos )       # or word w/o internal caps
			|
			( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos )       # or some other word
		) (_*) \b
	}{
		$1 . (
		  defined $2 ? $2         # preserve URL, domain, or email
		: defined $3 ? "\L$3"     # lowercase small word
		: defined $4 ? "\u\L$4"   # capitalize word w/o internal caps
		: $5                      # preserve other kinds of word
		) . $6
	}xeg;


	# Exceptions for small words: capitalize at start and end of title
	s{
		(  \A [[:punct:]]*         # start of title...
		|  [:.;?!][ ]+             # or of subsentence...
		|  [ ]['"“‘(\[][ ]*     )  # or of inserted subphrase...
		( $small_re ) \b           # ... followed by small word
	}{$1\u\L$2}xig;

	s{
		\b ( $small_re )      # small word...
		(?= [[:punct:]]* \Z   # ... at the end of the title...
		|   ['"’”)\]] [ ] )   # ... or of an inserted subphrase?
	}{\u\L$1}xig;

	# Exceptions for small words in hyphenated compound words
	## e.g. "in-flight" -> In-Flight
	s{
		\b
		(?<! -)					# Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (in-flight)
		( $small_re )
		(?= -[[:alpha:]]+)		# lookahead for "-someword"
	}{\u\L$1}xig;

	## # e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point)
	s{
		\b
		(?<!…)					# Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (stand-in)
		( [[:alpha:]]+- )		# $1 = first word and hyphen, should already be properly capped
		( $small_re )           # ... followed by small word
		(?!	- )					# Negative lookahead for another '-'
	}{$1\u$2}xig;

	print "$_";
}

__END__

Changes:

Thu, 06 Nov 2014

- Removed /o switch from substitutions; it's out-dated and described now as only "pretending" to optimize
- Special cases for small words in two-word compounds, like "stand-in" and "in-flight" (but not "man-in-the-middle")

Shell:

result=`echo $POPCLIP_TEXT | perl titlecase.pl`

/bin/echo -n $result

See Improved Title Case Macro for inspiration if not the working macro itself.

Thank you for the link, I have come across this before and it looks great. Is it possible to change macro so it can batch rename a selection of filenames in Finder, or is it only possible on clipboard text? PopClip serves the function well for me when individually renaming filenames as is applies a copy/paste principle (similar to this macro). But I'm looking to do a batch rename on a selection of filenames.

Your thoughts would be much welcomed in how to achieve this.

This macro will convert a selection of file names in the Finder to title case. I've restricted it to the base name, avoiding the extension because extensions have a life of their own. And I haven't tested it much.

It does prompt you to confirm each change, but that can be skipped if it infailingly works as expected.

NB: Changing case in a case-insensitive operating system doesn't change the filename. So I've resorted to the Perl rename function to work around this little hitch.

Batch Rename with Title Case Macro (v9.0.5)

Batch Rename with Title Case.kmmacros (8.5 KB)

2 Likes

Apologies for the delay in replying, only just logged into the forum to see your solution. Thank you so much for your efforts! Just tested the macro and it works great! Very much appreciated! Thank you :grinning:

@mrpasini I've been testing this macro and all works beautifully on Finder items. Again thank you so much for your help! If I could expand my original request slightly... Is it possible to run this macro by changing 'Finder' to 'DEVONthink'?

I've attempted and failed on my attempts at running this macro on files stored within DEVONthink. The intended workflow would be to select a number of files stored in DEVONthink and trigger the Batch Rename with Title Case Macro.

Searching the forum for a solution has unfortunately offered no help.

I'd be grateful for your thoughts. Thank you in advance :grinning:

@shanden, glad to hear it's working for you in the Finder.

I don't use DEVONthink so I downloaded the demo and took a look. I assume you are trying to rename a selection of files listed after an Import in the center panel.

I tried the Rename Using Regex script on the Script menu and that worked so I took a look at the Execute > Perl Script script to see how the Perl script used by our macro could be called within the AppleScript.

AppleScript and Perl can be folded into a Keyboard Maestro, of course. Or an AppleScript calling a Perl file could be added to the Script menu. Or both.

I'll take a deepr look at it later. Meanwhile, correct me if my impressions are wrong.

@mrpasini, thank you so much for the extra effort! That's so very kind of you to download DEVONthink and help with this! Greatly appreciated as I'm really struggling to wrap my head around KM and Applescript.

Yes, from research I believe DEVONthink can run an applescript with the do script function... how I implement that, I have no clue.

That would be my ideal situation, as once I know how perl can be used in applescript within DEVONthink, I can adapt other scripts as needed.

Appreciate the help and thank you so much again!

@shanden, I think this DEVONthink-only solution works (but let me know).

It has two parts:

  • AppleScript file: Batch Rename Using Title Case.applescript

  • Perl file: titlecase.pl

You'll have to manually install them and make one small edit.

  • Copy the AppleScript file to /User/[your user name]/Library/Application Scripts/com.devon-technologies.think3/Menu/Rename

  • Copy the Perl file to some nice, tidy place for all your DEVONthink perl files. Remember where.

The small edit is in the AppleScript file where you'll find my directory:

/Users/mrpasini/Desktop/titlecase.pl

which should be replaced by the location you copied the Perl file on your system.

That will list the AppleScript in the Rename menu of the Scripts menu. To run it, first make a selection in the file list then select the AppleScript from that menu.

I've also enclosed a Keyboard Maestro macro that calls the AppleScript located in the Application Scripts folder. So edit that location, too.

NB: The AppleScript has a Display Dialog command commented out in case you run into trouble and want to see what the script thinks it should be doing.

DT-BatchRename.zip (6.8 KB)

Let me know if that takes care of that.

2 Likes

@mrpasini, You absolute legend! Thank you so much! I've been trying figure out how to do this for 3 months! Thank you, thank you, thank you! You've made my day! :grinning:

3 Likes

Happy to help!

1 Like

Now @mrpasini gets to walk around the neighborhood saying "I.AM.LEGEND". I kind of think he was saying that before @shanden's comment. :rofl:

Good Job @mrpasini!