Combining two file-path segments, without missing or doubled "/"

Adding file names to folder paths (and combining filepath segments generally) can easily go wrong.

  • does the left-hand segment already end with a "/" ?
  • does the right-hand segment already start with one ?

Four combinatorial possibilities, which provide a rich source of confusions like the one just reported here:

KM10 change in Search RegExp or Finder Selection Collection - Questions & Suggestions - Keyboard Maestro Discourse

If you're using Execute an AppleScript actions, or Execute a JavaScript for Automation actions, it's useful to be able to reach for a pre-cooked combine function which just:

  • takes two file path segments and returns their concatenation
  • letting you forget about the problem of doubled or missing "/"

I personally use these:

AppleScript:

-- combine (</>) :: FilePath -> FilePath -> FilePath
on combine(fp, fp1)
    -- The concatenation of two filePath segments,
    -- without omission or duplication of "/".
    if "" = fp or "" = fp1 then
        fp & fp1
    else if "/" = item 1 of fp1 then
        fp1
    else if "/" = item -1 of fp then
        fp & fp1
    else
        fp & "/" & fp1
    end if
end combine

JavaScript:

// combine (</>) :: FilePath -> FilePath -> FilePath
const combine = fp =>
    // The concatenation of two filePath segments,
	// without omission or duplication of "/".
    fp1 => Boolean(fp) && Boolean(fp1) ? (
        "/" === fp1.slice(0, 1) ? (
            fp1
        ) : "/" === fp.slice(-1) ? (
            fp + fp1
        ) : `${fp}/${fp1}`
    ) : fp + fp1;

and FWIW I keep one for Python too:

# combine (</>) :: FilePath -> FilePath -> FilePath
def combine(fp):
    '''The concatenation of two filePath segments,
       without omission or duplication of '/'.
    '''
    def go(fp1):
        if not fp or not fp1:
            return fp + fp1
        elif '/' == fp1[0]:
            return fp1
        elif '/' == fp[-1]:
            return fp + fp1
        else:
            return fp + '/' + fp1
    return go

A simple way in Keyboard Maestro would be to just combine with with a “/” and then standardise the result.

image

Note that this will also get rid of any extraneous /./, adjust for /../ and convert from ~ to the home directory.

2 Likes

Perfect, and I hadn't realized that NSString.stringByStandardizingPath could eliminate duplicated //

(So even inside a KM Execute JavaScript for Automation, or AppleScript action, we could often skip combine and use that method)

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    const main = () =>
        filePath("~/Desktop//Doubled/");

    // --------------------- GENERIC ---------------------

    // filePath :: String -> FilePath
    const filePath = s =>
        // The given file path with any tilde expanded
        // to the full user directory path.
        ObjC.unwrap(
            ObjC.wrap(s).stringByStandardizingPath
        );

    return main();
})();

Expand disclosure triangle to view AppleScript Source
-- filePath :: String -> FilePath
on filePath(s)
    ((current application's ¬
        NSString's stringWithString:s)'s ¬
        stringByStandardizingPath()) as string
end filePath
1 Like