---
title: A Keyboard Shortcut to Clean Up Phone Numbers, IBANs, etc. Before Pasting
description: A small Hammerspoon module that removes unwanted formatting from common values while preserving email addresses and UUIDs.
date: 2026-07-22
url: https://aaron.cc/clean-up-values-before-pasting/
---


Do you know those situations where you copy something to the clipboard—such as a phone number, a credit card number, or an IBAN—to paste it into a web form, but the form is annoyingly strict and won’t allow spaces, dashes, or parentheses?

To solve this, I came up with a little [Hammerspoon](https://www.hammerspoon.org) module that binds to **⌃⌘V** and strips everything except ASCII letters, digits, and plus signs.

**Examples:**

* +49 30 23125-123 → +493023125123
* (030) 23125-123 → 03023125123
* GB33 BUKB 2020 1555 5555 55 → GB33BUKB20201555555555

**Bonus features:**

* It uses `hs.eventtap.keyStrokes()`, so it doesn’t perform an actual paste but instead simulates typing the string. This helps with form fields that, for whatever reason, prevent you from pasting into them.
* If you accidentally apply it to a canonical UUID or a string containing an @ sign—typically an email address—it preserves the punctuation and only trims surrounding whitespace.

```
local module = {}

-- Compact identifiers commonly consist only of ASCII letters, digits, and +.
local function sanitizeIdentifier(text)
  return text:gsub("[^A-Za-z0-9+]", "")
end

local function trim(text)
  return text:match("^%s*(.-)%s*$")
end

local function shouldPreserveFormatting(text)
  -- Punctuation is meaningful in email addresses and canonical UUIDs.
  if text:find("@", 1, true) then
    return true
  end

  return text:match("^%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x$") ~= nil
end

local function pasteIdentifier()
  local text = hs.pasteboard.getContents()
  if not text then
    hs.alert.show("Clipboard does not contain text")
    return
  end

  local trimmedText = trim(text)
  local value = shouldPreserveFormatting(trimmedText) and trimmedText or sanitizeIdentifier(text)

  module.pasteTimer = hs.timer.doAfter(0.05, function()
    module.pasteTimer = nil

    -- Let the shortcut's physical Ctrl and Cmd keys come up first. Typing the
    -- cleaned value directly avoids swapping and synchronizing the clipboard.
    hs.eventtap.keyStrokes(value)
  end)
end

function module.start()
  module.hotkeys = {
    hs.hotkey.bind({ "ctrl", "cmd" }, "v", pasteIdentifier),
  }
end

return module
```

Save it as `identifier_paste.lua` and include in your init.lua like so:

```
require("modules.identifier_paste").start()
```
