Macro: Common Conversions

Conversions 10a.zip (13.3 KB)

ABOUT

This package contains two macros that call the same Perl script to convert from one unit of measure to another or perform a caluation on a selection when you press the trigger key.

In the text editor version, the trigger key is Control-Option-Equals. In the browser version, which is intended for a palette, the trigger key is the Equals sign.

INTRO

Once upon a time Peter Lewis wrote a macro called Calculate Macro (Calculate Macro) that would return the result of an equation if you preceded it with a particular (and unique) string of characters.

I liked that idea. I'd been using a service and then Spotlight to do that. But, as with so many other things, Keyboard Maestro was able to replace those approaches.

But I preferred triggering the function on a selection rather than a typed string. That allows me to revise the calculation endlessly before selecting it and getting the result. I could even undo the calculation to make more edits.

Then I thought why restrict it to just a calculation? Why not do some common conversions that slow me down in the press releases I edit.

So I expanded the macro to handle those too. But there were a lot of them and the visual nature of Keyboard Maestro's programming tools made it hard to see which branch of an if-else action I was in.

So I just rewrote the thing in Perl.

I set the macro to run when you type Control-Option-Equals on a selection. And made it active in my text and word processing applications. The idea was to replace the selection with the conversion.

But then I starting wishing I had access to it when Web browsing to convert unfamiliar metric measurements into more familiar imperial ones. How far is 1,300km? Oh, it's 808 miles.

So I wrote a version for my Safari palette (which is why the trigger is just one character, so beware) which also works in other browsers (Chrome, Firefox and Vivaldi were tested) that reads a selection and pops up a dialog with the conversion, while putting the conversion on the System Clipboard in case I want to paste it somewhere, too.

That's why there are two of these.

INSTALLATION

But they both use the same 104 lines of Perl code. No sense repeating that in each macro when the Execute Shell Script can reference an external file.

And with a little test at the top of that Perl file, we can run the same code either within a Keyboard Maestro macro or as a BBEdit/TextWrangler text filter.

Which is why there are three other files (including this one) in this distribution.

Put the Conversions.hybrid.pl Perl file in your text filters folder or anywhere you like and point Execute Shell Script in the two macros to it. You're set for life.

You might be interested in a couple of other changes.

You could just copy the Conversions.hybrid.pl file into the Execute Script action instead of keeping a copy outside Keyboard Maestro. If you do that, you can change the test at the top to the simple assignment:

	$str = $ENV{KMVAR_kmVar};

If you are using the browser macro, you could also eliminate the JavaScript by having the Execute Shell Script action display the results briefly or in a window, if you prefer. We're using JavaScript in the browser version because we prefer the look of its dialog.

DEFAULT CONVERSIONS

The conversions, based on formulas from CEVA (http://www.cevaground.com/Customers/Conversions/ConversionFormula.aspx). Conversions, are handled in three groups. First we handle an aspect ratio conversion for embedded videos (just to get that out of the way) which I find useful. Then we handle calculations, keeping them distinct from the main body of conversions, which is the third group.

Conversions in the third group can go both ways. You can select someting in centimeters to get inches and something in inches to get centimeters, for example. Whitespace is adroitly handled so that 10km and 10 km are equally understood (although one is bad form).

The default conversions include:

  1. That esoteric width/height conversion that calculates the correct heights for two of my preferred widths, useful for embedding videos. Any width other than 500 is set to 500 before the height is calculated but any 500 pixel width is set to 480 before the height is calculated. So if I need a 480px wide video, I just run the thing twice.

  2. Any selection with an operator (+ - / *) is calculated. Parentheses will also trigger a calculation.
    For example, "abs(-5)" will return "5" and log(2.71828183)" will return "1.00000000056689."

  3. Common conversions, the meat of this dish, include:
    cm - inches
    mm - inches
    g - ounces
    kg - pounds
    m under 100 - feet
    m over 100 - yards
    km - miles
    °C - °F
    NB: Inches and feet are converted from " and ' symbols but not to them.
    Only the degree symbol (Shift-Option-8) and not the masculine ordinal (Option-0) will trigger temperature conversions (see https://www.howtotype.net/symbol/Degree_symbol/). If the academic space is used, it will be maintained. Varied results on the Web (Weather Underground (https://www.wunderground.com) works, local news sites don't).
    Commas are legal in selections but stripped before any calculations are done. But persist in the original selection.

Any selection not converted will be returned unharmed to your text.

CURRENCY

Due to constantly varying rates, this macro does not attempt currency conversion.

REPEAT ORIGINAL VALUE

If you wish to repeat an original value (other than a width/height conversion or a calculation) in parentheses, simply include a trailing space at the end of your selection.
For example, selecting '12 lbs. ' will return '5.44kg (12 lbs.) ' with the trailing space.

EXAMPLES

I debugged the Perl code in TextWrangler where I was able to throw a variety of data at it to see what happens. The data and the results shown below are delimited by single quotes:

Embedded video resizing:
'width="560" height="315"' = 'width="500" height="281"'
'width="500" height="281"' = 'width="480" height="270"'

Calculations:
'(1+2+3)/3' = '2'
'log(2.71828183)' = '1.00000000056689'
'abs(-10) + abs(10)' = '20'

Conversions:
'50cm' = '19.68 in.'
'12g' = '0.42 oz.'
'12 lbs.' = '5.44kg'
'24gm' = '0.84 oz.'
'67mm' = '2.63 in.'
'12g ' = '0.42 oz. (12g) '
'12 lbs. ' = '5.44kg (12 lbs.) '
'24gm ' = '0.84 oz. (24gm) '
'67mm ' = '2.63 in. (67mm) '
'120kg' = '264.00 lbs.'
'110m' = '120 yards'
'12m' = '39.37 ft.'
'80km' = '50 miles'
'120 ft' = '40.00 yards'
'20 in.' = '50.80cm'
'120'' = '40.00 yards'
'20"' = '50.80cm'
'42 oz.' = '1.19kg'
'120 yards' = '110m'
'50 miles' = '80km'
'59°F' = '15°C'
'23°C' = '73°F'
'2300°K' = '2300°K'
'59 °F ' = '15 °C (59 °F) '
'15°C ' = '59°F (15°C) '
'79 °F' = '26 °C'
'17 °C' = '63 °F'

Not Converted:
'log(2.71828183) ~ 1.00' = 'log(2.71828183) ~ 1.00'
'23 tons' = '23 tons'

ROLL YOUR OWN

You can add your own conversions to the Perl script. There are two places to check in any particular group.

The first is in the if-elsif regex that defines the group. Make sure your label or symbol is included. For the common conversions section of the Perl code, you would look at:

	} elsif ($str =~ /([\.\d]+?) ?([a-z'"]+?\.?) ?$/) {

to confirm it will recognize your label. For example, we had to add the quote marks to handle common foot (') and inch (") labels. But "ml" would already be included in the "a-z" range.

After confirming your label will be recognized, add an elsif statement in that section of the group's code using the following template:

	} elsif ($str =~ /[search string]/) {
		$ans = eval($calc * [conversion value]);
		$ans = sprintf("%.2f [converted label]",$ans);

where:

  1. 	[search string] is a regex for what you're looking for
    
  2. 	$calc * [conversion value] is the conversion formula
    
  3. 	%.2f [converted label] is the output format (here with two decimals)
    

You'll need one more of these to convert back, of course.

I have them collected in imperial and metric sections but you can organize them however you like, the code doesn't mind.

How do you know when to create a new group?

The groups cascade from longer regex descriptions to shorter ones. In fact, some of the longer ones would be processed by the short one if we didn't trap it earlier. They aren't mutually exclusive.

So if you wanted to look for cubic inches or liquid ounces, which would require a double label, you'd want to put that above the third group that does most of the work. The regex that would describe that group would include both labels and safely handle the conversion before the third group got its hands on it.

SUPPORT

I'm happy to promptly address any concerns you may have.

5 Likes

Thank you, great posting! I took the liberty to repost your posting in our Cafetranslators forum: https://cafetran.freshdesk.com/support/discussions/topics/6000050661

Glad you found it useful. CafeTran looks like an interesting product.

Not sure why your version doesn’t support degrees translation between C and F.

I should point out that I used 2300°K to show what happens when applied to a selection with no conversion value (you get it right back). But C to F should work.

I can see why, in a translation, you would not want to support the trailing space option, though.

Thanks for getting back on this. Did some further testing. Now the C/F conversion doesn't work in TextWrangler either. When I only select the °F, I get -18°C. When I select the °C I get 32°F – so a certain calculation takes place. When I select a number plus °F or °C, nothing happens.

Looking at the script I noticed that you wrote "F" whereas all other strings where enclosed by //:

Changing this to /F/ didn't solve it, alas. And that's where my knowledge of Perl stops :wink: :

Thanks for catching that. I had included an older hybrid Perl file in the archive by mistake.

I’ve updated the original distribution to include the correct one (with a 29 August 2017 revision date). It does not handle the temperature conversions separately.

Sorry for the mix up. And thanks again.