How Do I Remove Year Range (YYYY-YYYY) from All Text on Clipboard?

Hello guys,
I do alot of copy and paste of data, but I always need to manually remove YYYY from the data am working on,
anyway I can create a macro to auto remove from clipboard YYYY
sample like this

1 Like

You might strip off the last 4 or 5 characters (don't know if you want the dash) with a "Get Substring" action. I also filtered with "Trim Whitespace" in case your text has trailing white space.

Keyboard Maestro 8.2.1 “Delete XXXX” Macro

Delete XXXX.kmmacros (1.7 KB)

Or you could use a Regular Expression to accomplish the same thing (the RegEx can determine if the characters are digits or non-digits).

Keyboard Maestro 8.2.1 “Delete XXXX RegEx” Macro

Delete XXXX RegEx.kmmacros (1.7 KB)

Your requirements are not clear.
It is best to post a complete real-world example of your source data, and the resultant text after the operation.


  1. Do you want to remove YYYY everywhere in the text, or only if it occurs exactly as shown in your example?
  2. Remove only YYYY, or the pattern YYYY-YYYY ?
  3. If the pattern YYYY-YYYY is removed, and nothing else is on the line, do you want to also remove the line?

Either for an Execute Applescript action, or an Execute Javascript for Automation action:

Applescript source

use AppleScript version "2.4"
use scripting additions

on run
    set clip to the clipboard
    if class of clip is text then
        set strPruned to unlines(map(untilDigit, |lines|(clip)))
        set the clipboard to strPruned
        return strPruned
    end if
end run

-- untilDigit :: String -> String
on untilDigit(s)
    takeWhile(my notDigit, s)
end untilDigit

-- notDigit :: Char -> Bool
on notDigit(c)
    not isDigit(c)
end notDigit

-- GENERIC FUNCTIONS ----------------------------------------------------


-- isDigit :: Char -> Bool
on isDigit(c)
    set n to (id of c)
    48 ≤ n and 57 ≥ n
end isDigit

-- lines :: String -> [String]
on |lines|(xs)
    paragraphs of xs
end |lines|

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
            property |λ| : f
        end script
    end if
end mReturn

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- takeWhile :: (a -> Bool) -> [a] -> [a]
on takeWhile(p, xs)
    set bln to false
    set blnText to (class of xs) is text
    tell mReturn(p)
        repeat with i from 1 to length of xs
            if not |λ|(item i of xs) then
                set bln to true
                exit repeat
            end if
        end repeat
    end tell
    if bln then
        if i > 1 then
            if blnText then
                text 1 thru (i - 1) of xs
                items 1 thru (i - 1) of xs
            end if
            if blnText then
            end if
        end if
    end if
end takeWhile

-- unlines :: [String] -> String
on unlines(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
end unlines

Javascript source

(() => {
    'use strict';

    const main = () => {

        // untilNumber :: String -> String
        const untilNumber = takeWhile(c => !isDigit(c));

            sa = standardAdditions(),
            clip = sa.theClipboard();

        return 'string' === typeof clip ? (() => {

            const strPruned = unlines(
                map(untilNumber, lines(clip))
            return (
        })() : '';

    // GENERIC FUNCTIONS -----------------------------


    // isDigit :: Char -> Bool
    const isDigit = c => {
        const n = ord(c);
        return 48 <= n && 57 >= n;

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

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

    // ord :: Char -> Int
    const ord = c => c.codePointAt(0);

    // takeWhile :: (a -> Bool) -> [a] -> [a]
    const takeWhile = p => xs => {
        let i = 0;
        const lng = xs.length;
        while ((i < lng) && p(xs[i]))(i = i + 1);
        return xs.slice(0, i);

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

    // JXA --------------------------------------------

    // standardAdditions :: () -> Application
    const standardAdditions = () =>
        Object.assign(Application.currentApplication(), {
            includeStandardAdditions: true

    // MAIN ---
    return main();

Dimension Graphic Design
John Monaco 2000-2002 Information

Craig Smith 1995-2000 Information

Dimension Graphic Design
John Monaco

Craig Smith

I copy data from file to file.i dont know if possible to make macros that will auto delete YYYY, and state from the data.. like this example

copy and paste

Given this text:

The below macro will produce this:

Example Output


If you wish to automatically paste the results, you will need to enable the last Action:

This macro should do the trick, or at least give you an example to get you started.
Also note that I have expanded the RegEx so that it will match a year range at either the start or end of a line, like this:

2017-2018 some text at end
some text at start 2010-2011


For detailed explanation, see regex101: build, test, and debug regex

Note that this uses the metacharacter \h to match any horizontal whitespace. It is only supported by the latest versions of KM and macOS. If it does not work for you, you can use [\t ] instead.

As always, feel free to post any questions, issues, comments, and/or suggestions that you might have about this macro.

MACRO:   Remove Year Ranges From Clipboard Text @RegEx [Example]

<img src="/uploads/default/original/2X/9/9fa034801953dfe7d1745afcb7087c7530a06e23.gif" width="70" height="17"  alt="updated" title="updated"> 2018-07-08 17:10 GMT-5
  • Revised RegEx to match year range at start & end of line.
<a class="attachment" href="/uploads/default/original/3X/1/d/1db14dcc157f4c695d70aad80d6ee73b10d39082.kmmacros">Remove Year Ranges From Clipboard Text @RegEx [Example].kmmacros</a> (5.4 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**



Just updated Macro in my above post.

Sample ... Results:


In a script action, you might use something like:

// untilNumber :: String -> String
const untilNumber = takeWhile(c => !isDigit(c));

( Samples edited in previous post, above )

Thank you @JMichaelTX

Everything almost perfect but 2 more things needed

  • how can I set Macros to Remove STATES e.g Texas , Florida etc ..
  • how can I set Macros to remove empty Line e.g

Dimension Graphic Design
Information ( delete this info and delete the line)
John Monaco

Information ( delete this info and delete the line)
Craig Smith


Dimension Graphic Design
John Monaco

Craig Smith

Also big thanks to other people who supported ...

Assuming that the data is always positioned on the lines as shown, and you want to keep line 1 (Company) and line 3 (Contact), then you could use this RegEx:

Search for:

Replace with:

This will remove all empty lines:

Search for:

Replace with:


Any way to set macros to remove state from the middle of a text? e.g
Dimension Graphic Design
John Monaco ILLINOIS Information

The empty line still remain after adding this:
Search for:
Replace with:

How did it get in the middle? Did it happen after one of the other RegEx Search/Replace?

It is best to provide us with ALL of your requirements at the beginning.

Again, we need a complete, real-world example of your source text without any changes. The text you receive/get to start your workflow.
It is too time-consuming and confusing to do this piecemeal.

Am really sorry if I cost you time-consuming.
the macros works very good for the YYYY. I was able to set the remove information but the LINE remain empty and I wish to close the gap.
I try \n but it added additional extra LINE.

here is the real format of the text am working on

John Monaco
ID: 123 456 789 1995-2000 ILLINOIS Dimension Graphic Design

Craig Smith
ID: 234 567 890 2000-2002 TEXAS A Reason To Smile

The YYYY working perfect

Only need information to delete and close the gap
and also the state

OK, that is good. Show me the FINAL result you want.

John Monaco
ID: 123 456 789 Dimension Graphic Design

Craig Smith
ID: 234 567 890 A Reason To Smile

OK, given this source text:

The below macro will produce this:

Example Output


Search For:

Replace with:

Please let us know if this provides the complete solution for you.

MACRO:   Extract Selected Data from Text @RegEx [Example]

<a class="attachment" href="/uploads/default/original/3X/c/1/c15cff0afd412ea12719d754e04d9c0c3073c7d2.kmmacros">Extract Selected Data from Text @RegEx [Example].kmmacros</a> (8.8 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**


### ReleaseNotes

	1.	Select the text you want to process
	2.	Trigger this macro

If you want to paste the result back into the same document (replacing the selection), then ENABLE the last Paste Action.



Making Requests for Text Manipulation

Just a follow-up for @moonlightru, and everyone who makes a request, In your initial topic/request, to get the best results in the shortest amount of time, please post:

  1. Your complete requirements
  2. Complete real-world source text that will be representative of all cases.
  3. Exactly what you want the results to look like.

In this topic, it took me only about 15 min to develop the solution to the final request which included everything that needed to be done.

Unfortunately, both of us wasted much more than that, and it took several days to get the final solution. Had the above been provided in the beginning, it is likely that the solution could have been provided within the same day it was posted.


1 Like

Well put.

We can't get from input to output unless you show us both.
( Show works better than tell ).

( Even in math, constructive proofs are more productive )

@JMichaelTX, @ComplexPoint

Everything is perfect ... You guys are the BEST!!!

Thanks so much....!!!!!

1 Like