Regular Expression (RegEx) to Filter by Date

Second draft, using regexes for that date and currency amount pattern:

(there are, of course, non-JS routes as well, once you are using regexes)

Regex processing and Date filtering in an Execute Javascript action.kmmacros (22.1 KB)

If you are going to consolidate different currencies into one sum then you will need to deal with exchange rates, of course :slight_smile:

tidied

JS second draft

(() => {
    'use strict';

    const main = () => {
        const
            rgxDateVal = /(\d+)\/(\d+)\/(\d+)\s+(\d+)\:(\d+)\s+(\d+)\s+(\w+)/,
            strData = Application('Keyboard Maestro Engine')
            .getvariable('dateTimeValues'),
            xs = concatMap(
                x => {
                    const m = rgxDateVal.exec(x);
                    return Boolean(m) ? [({
                        // y, m, d, h, m, s
                        dateTime: new Date(
                            ...[m[3], m[2] - 1, m[1], m[4], m[5]]
                            .map(s => parseInt(s, 10))
                        ),
                        amount: parseInt(m[6], 10),
                        currency: m[7]
                    })] : [];
                },
                lines(strData)
            );
        const
            dteNow = new Date(),
            dte24Hago = (new Date()).setDate(
                dteNow.getDate() - 1
            ),
            dte7Daysago = (new Date()).setDate(
                dteNow.getDate() - 7
            ),
            last24Hs = filter(
                x => x.dateTime >= dte24Hago,
                xs
            ),
            last7Ds = filter(
                x => x.dateTime >= dte7Daysago,
                xs
            );

        // periodSums :: [Dict] -> String
        const periodSums = events =>
            unlines(map(
                c => foldl(
                    (a, x) => c !== x.currency ? (
                        a
                    ) : a + x.amount,
                    0,
                    events
                ).toString() + ' ' + c,
                nub(map(
                    x => x.currency,
                    events
                ))
            ));
            
        return `
Last 24 hours:
${unlines(map(
    x => x.dateTime.toString() + ' ' + x.amount + ' ' + x.currency,
    last24Hs
))}

Total Sums for last 24 hours:
${periodSums(last24Hs)}

Last 7 days:
${unlines(map(
    x => x.dateTime.toString() + ' ' + x.amount + ' ' + x.currency,
    last7Ds
))}

Total Sums for last 7 days:
${periodSums(last7Ds)}
`
    };

    // GENERIC FUNCTIONS ----------------------------
    // https://github.com/RobTrew/prelude-jxa

    // concatMap :: (a -> [b]) -> [a] -> [b]
    const concatMap = (f, xs) =>
        xs.reduce((a, x) => a.concat(f(x)), []);

    // eq (==) :: Eq a => a -> a -> Bool
    const eq = (a, b) => {
        const t = typeof a;
        return t !== typeof b ? (
            false
        ) : 'object' !== t ? (
            'function' !== t ? (
                a === b
            ) : a.toString() === b.toString()
        ) : (() => {
            const aks = Object.keys(a);
            return aks.length !== Object.keys(b).length ? (
                false
            ) : aks.every(k => eq(a[k], b[k]));
        })();
    };

    // filter :: (a -> Bool) -> [a] -> [a]
    const filter = (f, xs) => xs.filter(f);

    // foldl :: (a -> b -> a) -> a -> [b] -> a
    const foldl = (f, a, xs) => xs.reduce(f, a);

    // lines :: String -> [String]
    const lines = s => s.split(/[\r\n]/);

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // nub :: [a] -> [a]
    const nub = xs => nubBy(eq, xs);

    // nubBy :: (a -> a -> Bool) -> [a] -> [a]
    const nubBy = (p, xs) => {
        const go = xs => 0 < xs.length ? (() => {
            const x = xs[0];
            return [x].concat(
                go(xs.slice(1)
                    .filter(y => !p(x, y))
                )
            )
        })() : [];
        return go(xs);
    };

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // MAIN ---
    return main();
})();
2 Likes