<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://motionobj.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://motionobj.com/" rel="alternate" type="text/html" /><updated>2026-07-28T08:33:41+00:00</updated><id>https://motionobj.com/feed.xml</id><title type="html">MotionObj</title><subtitle>MotionObj builds indie web and macOS software products, including web tools and small Mac apps by Hwee-Boon Yar and Daphane Khoo.</subtitle><entry><title type="html">How to Move a Mac App’s Settings and Local Data to a New Mac</title><link href="https://motionobj.com/articles/move-mac-app-settings-local-data-new-mac/" rel="alternate" type="text/html" title="How to Move a Mac App’s Settings and Local Data to a New Mac" /><published>2026-07-25T04:10:00+00:00</published><updated>2026-07-25T04:10:00+00:00</updated><id>https://motionobj.com/articles/move-mac-app-settings-local-data-new-mac</id><content type="html" xml:base="https://motionobj.com/articles/move-mac-app-settings-local-data-new-mac/"><![CDATA[<p>The safest way to move a Mac app is not to drag its icon to the new Mac and hunt for missing files afterward. I start with Migration Assistant, then verify each app’s documents, local data, accounts, and licence.</p>

<p>Migration Assistant handles more than the app bundle. Apple says it can transfer apps, user accounts, documents, files, privacy and security settings, and system and network settings. It can transfer directly from the old Mac or from a Time Machine backup.</p>

<p><strong>Back up the old Mac before starting, and do not erase it until the new copy has been checked.</strong></p>

<h2 id="prepare-the-old-and-new-macs">Prepare the old and new Macs</h2>

<p>I do this before opening Migration Assistant:</p>

<ol>
  <li>Install available macOS updates on both Macs.</li>
  <li>Update important apps, unless the developer requires a particular version for migration.</li>
  <li>Finish app imports, database repairs, and sync activity.</li>
  <li>Use the app’s export or backup command when it has one.</li>
  <li>Run a Time Machine backup and wait for it to complete.</li>
  <li>Record where irreplaceable documents are stored and whether they are local, in iCloud, or in another service.</li>
  <li>Keep licence keys, purchase records, and vendor sign-in details available without placing passwords in an unencrypted note.</li>
</ol>

<p>For a manual inventory, I check <a href="/articles/where-mac-apps-store-data-and-settings/">where the app stores its data and settings</a>. I use the separate <a href="/articles/back-up-restore-mac-app-settings-local-data/">backup and restore checklist</a> before changing any app-managed files.</p>

<h2 id="use-migration-assistant-for-the-main-transfer">Use Migration Assistant for the main transfer</h2>

<p>On a current version of macOS:</p>

<ol>
  <li>Open <strong>System Settings → General → Transfer or Reset</strong>.</li>
  <li>Click <strong>Open Migration Assistant</strong>.</li>
  <li>On the new Mac, choose to transfer from a Mac, Time Machine backup, or startup disk.</li>
  <li>Follow the matching instructions on the old Mac or connect the backup.</li>
  <li>Select the user account and the applications, files, and settings that need to move.</li>
  <li>Let the transfer finish and read the migration summary for anything that could not be transferred.</li>
</ol>

<p>Apple’s <a href="https://support.apple.com/guide/mac-help/mh27921/mac">Transfer your information to Mac from another computer or device</a> guide lists the current choices and preparation steps.</p>

<p>Apple also warns that incompatible apps, or apps with newer versions already installed, may not transfer or may not be usable. I treat Migration Assistant as the broad transfer, not proof that every app is ready.</p>

<h2 id="reinstall-apps-from-the-right-source-when-needed">Reinstall apps from the right source when needed</h2>

<p>If an app did not transfer or does not open, I download a compatible version from the Mac App Store, the developer, or the service where I originally obtained it.</p>

<p>The App Store and direct-download editions of an app can use different bundle identifiers, containers, licences, or features. Even when their names and icons match, I do not copy one edition’s container over the other unless the developer documents that migration.</p>

<p>Mac App Store apps use App Sandbox. Direct-download apps may be sandboxed or may use traditional locations such as <code class="language-plaintext highlighter-rouge">~/Library/Application Support</code> and <code class="language-plaintext highlighter-rouge">~/Library/Preferences</code>. Related extensions can also store shared data in <code class="language-plaintext highlighter-rouge">~/Library/Group Containers</code>.</p>

<h2 id="let-cloud-data-and-local-data-finish-separately">Let cloud data and local data finish separately</h2>

<p>After signing in to the same Apple Account, I check <strong>System Settings → my name → iCloud</strong>. Apple says apps enabled there can store and sync their information through iCloud.</p>

<p>I give the app time to finish downloading or indexing before deciding that data is missing. iCloud Drive may keep an item in iCloud without a full local download when Optimize Mac Storage is enabled. Finder’s <strong>Download Now</strong> command downloads a selected cloud-only item.</p>

<p>App-specific accounts need the same care. A database may sync from the vendor after sign-in, while plug-ins, local presets, downloads, or unsynced records still need the old Mac or backup.</p>

<p>I do not mix a manual restore into an active sync until the app developer’s instructions explain which copy wins. A stale local database can overwrite newer cloud data, or the service can replace the local restore.</p>

<h2 id="check-passwords-and-licences">Check passwords and licences</h2>

<p>Apple says Setup Assistant transfers keychains automatically during migration. Local Items and iCloud Keychain passwords are not files to copy manually; they become available on the new Mac by signing in to the same Apple Account and enabling Passwords and Keychain sync.</p>

<p>Apple documents the distinction in <a href="https://support.apple.com/guide/keychain-access/kyca1121/mac">Copy keychains to another Mac</a>.</p>

<p>An app licence is a separate question. Migration Assistant does not promise that every vendor activation, Mac App Store receipt, subscription session, or machine-bound licence will remain valid. I open the app’s purchase or licence documentation and sign in, restore purchases, deactivate the old Mac, or activate the new one as required.</p>

<p>I never copy authentication tokens or random Keychain databases into an app container to avoid signing in.</p>

<h2 id="use-a-manual-restore-only-for-a-known-gap">Use a manual restore only for a known gap</h2>

<p>If Migration Assistant and the app’s own sync or import leave known data behind, I restore that specific data from the backup.</p>

<p>I make a backup of the new Mac’s current app data first, quit the app and its helpers, and restore only known app-owned folders to their documented locations. I do not replace the whole <code class="language-plaintext highlighter-rouge">~/Library</code>, another app’s group container, or every file containing the developer’s name.</p>

<p>On macOS 15 and later, app data and group containers can have additional System Integrity Protection. A permission prompt or an app that rejects a copied container can be expected protection, not evidence that repeatedly changing ownership or permissions is safe.</p>

<p>If the old and new app versions use different database formats or sandbox entitlements, I stop and use the developer’s supported import or migration path.</p>

<h2 id="verify-the-transfer-before-erasing-the-old-mac">Verify the transfer before erasing the old Mac</h2>

<p>I open every app that holds data I cannot recreate and check:</p>

<ul>
  <li>old and recent documents or records</li>
  <li>attachments, media, and linked folders</li>
  <li>search, tags, templates, presets, and plug-ins</li>
  <li>preferences that change storage locations or exports</li>
  <li>cloud and app-account sync status</li>
  <li>passwords, certificates, and connected services</li>
  <li>licence, subscription, and purchase status</li>
</ul>

<p>I also restart the new Mac and open the important apps again. That catches helpers, mounted folders, permissions, and credentials that worked only during the first session.</p>

<p>Once the new Mac has passed those checks, I run its own full backup. I keep the old Mac or its independent backup until I have used the migrated apps long enough to know that no local-only history or attachment is missing.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Move a Mac app's settings and local data to a new Mac with Migration Assistant, then verify documents, containers, sync, Keychain, and licences.]]></summary></entry><entry><title type="html">How to Back Up and Restore a Mac App’s Settings and Local Data</title><link href="https://motionobj.com/articles/back-up-restore-mac-app-settings-local-data/" rel="alternate" type="text/html" title="How to Back Up and Restore a Mac App’s Settings and Local Data" /><published>2026-07-25T04:05:00+00:00</published><updated>2026-07-25T04:05:00+00:00</updated><id>https://motionobj.com/articles/back-up-restore-mac-app-settings-local-data</id><content type="html" xml:base="https://motionobj.com/articles/back-up-restore-mac-app-settings-local-data/"><![CDATA[<p>Copying a Mac app from Applications does not usually back up its settings or local data. Copying one folder from Library may miss documents, app-group data, credentials, or cloud state.</p>

<p>I use the app’s own export first, Time Machine for the broad backup, and a manual copy only when I know which files the app owns.</p>

<p><strong>Make a backup before changing or restoring anything.</strong> Keep the original backup unchanged until the app opens and the important data has been checked.</p>

<h2 id="record-what-has-to-come-back">Record what has to come back</h2>

<p>Before making a manual backup, I write down:</p>

<ul>
  <li>the app name and version</li>
  <li>whether it came from the Mac App Store, the developer, or another service</li>
  <li>the folders containing documents I created</li>
  <li>the app-owned support, preference, container, and app-group folders</li>
  <li>whether the app syncs through iCloud or its own account</li>
  <li>how the app’s licence or subscription is restored</li>
</ul>

<p>The companion guide to <a href="/articles/where-mac-apps-store-data-and-settings/">where Mac apps store their data and settings</a> explains the common Library locations. I do not include a folder merely because its name resembles the app. Developer names, bundle identifiers, shared frameworks, and app groups can overlap.</p>

<h2 id="prefer-an-app-provided-export">Prefer an app-provided export</h2>

<p>If the app offers <strong>Export</strong>, <strong>Back Up</strong>, or <strong>Archive</strong>, I use it and read the vendor’s restore instructions at the same time. An export can preserve relationships between records that are spread across several internal files.</p>

<p>I inspect what the export includes. Some apps export content but omit preferences, attachments, plug-ins, accounts, or history. I keep the original documents and the broader Mac backup as well.</p>

<h2 id="use-time-machine-for-the-broad-backup">Use Time Machine for the broad backup</h2>

<p>Apple says Time Machine backs up files including apps, photos, email, and documents, and can restore files to the same or a different Mac. I connect the backup disk, choose <strong>Back Up Now</strong> from the Time Machine menu, and wait until the menu reports that the backup is done.</p>

<p>I also open <strong>System Settings → General → Time Machine → Options</strong> and check the exclusion list. Apple notes that excluded items are not copied to the backup disk, and in rare cases third-party software can mark its files so Time Machine does not back them up.</p>

<p>The current steps are in Apple’s <a href="https://support.apple.com/104984">Back up your Mac with Time Machine</a> and <a href="https://support.apple.com/guide/mac-help/mh15138/mac">If Time Machine doesn’t back up certain files</a> guides.</p>

<p>A Time Machine backup is my safety net. I still use an app export when the app provides one because the export is easier to inspect and may be more portable across app versions.</p>

<h2 id="make-a-manual-copy-only-after-identifying-the-files">Make a manual copy only after identifying the files</h2>

<p>For an app without an export, I use Finder to copy the known files and folders to a dated backup folder on separate storage.</p>

<ol>
  <li>Save work, finish any in-progress import or sync, and quit the app.</li>
  <li>Quit its menu bar item and helper if the app provides a documented way to do so.</li>
  <li>Copy the documents I created.</li>
  <li>Copy the app-owned support, preferences, container, and app-group folders that its documentation identifies.</li>
  <li>Keep the folder structure in the backup notes so I know each original location.</li>
  <li>Record the app version, download source, and restore instructions beside the files.</li>
</ol>

<p>I copy rather than move. I do not remove the originals to prove that the backup works.</p>

<p>Sandbox and app-group containers may be protected. A copy can require authorization, and another app or a different build of the same app may not be entitled to use the restored container. The appearance of a complete copy does not prove that macOS or the app will accept it later.</p>

<p>I usually leave caches and saved window state out of a focused manual backup. I include them only when the app’s documentation says they contain something that cannot be recreated.</p>

<h2 id="treat-synced-data-as-a-separate-copy">Treat synced data as a separate copy</h2>

<p>Apple says data for an app enabled in iCloud is stored in iCloud and kept in sync across devices. Sync can bring data to a replacement installation, but sync also propagates changes and deletions.</p>

<p>I check <strong>System Settings → my name → iCloud</strong> to see which apps use iCloud. For ordinary files in iCloud Drive, I use <strong>Download Now</strong> in Finder when an item is stored only in iCloud and I need a local copy. Apple documents this in <a href="https://support.apple.com/guide/mac-help/mchl1a02d711/mac">Work with folders and files in iCloud Drive</a>.</p>

<p>I do not overwrite local or cloud-backed data until I understand which copy the app treats as current. When the vendor specifies a sign-in or restore order, I follow it.</p>

<h2 id="restore-without-replacing-good-data">Restore without replacing good data</h2>

<p>For a small restore, I start with the app’s supported import command. For an item in Time Machine, Apple says to open the Finder window for the item’s original location, open Time Machine, select the item or version, and click <strong>Restore</strong>. The item returns to its original location.</p>

<p>Before restoring app-managed files:</p>

<ol>
  <li>Confirm that the backup predates the loss or bad change.</li>
  <li>Make another copy of the current files, even if they look broken.</li>
  <li>Install a compatible app version from the original source.</li>
  <li>Quit the app and its documented helpers.</li>
  <li>Restore only the files or folders whose ownership and original locations are known.</li>
  <li>Open the app and inspect the data before reconnecting a sync service or making more changes, when the vendor’s instructions allow that order.</li>
</ol>

<p>Apple’s current item-restore steps are in <a href="https://support.apple.com/guide/mac-help/mh11422/mac">Restore items backed up with Time Machine on Mac</a>.</p>

<p>If the app reports an incompatible database, missing account, damaged library, or permission error, I stop. I keep the current data and backup instead of repeatedly replacing files. The app developer is in the best position to explain its database versions, repair tools, and container entitlements.</p>

<h2 id="check-more-than-the-launch-screen">Check more than the launch screen</h2>

<p>After restoring, I check:</p>

<ul>
  <li>several old and recent records or documents</li>
  <li>attachments and linked files</li>
  <li>search, tags, presets, and plug-ins that matter</li>
  <li>preferences that affect where data is written</li>
  <li>account sign-in and sync status</li>
  <li>licence or subscription status</li>
</ul>

<p>Passwords and licences can be stored in Keychain or validated by a server. They may need a separate sign-in or activation even when local data restores correctly.</p>

<p>I keep the dated backup until the restored app has been used normally and another full backup has completed. For a replacement computer, I use <a href="/articles/move-mac-app-settings-local-data-new-mac/">Migration Assistant first, then verify the app’s settings and local data on the new Mac</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Safely back up and restore a Mac app's settings, documents, databases, sandbox containers, synced data, credentials, and licences.]]></summary></entry><entry><title type="html">Where Mac Apps Store Their Data and Settings</title><link href="https://motionobj.com/articles/where-mac-apps-store-data-and-settings/" rel="alternate" type="text/html" title="Where Mac Apps Store Their Data and Settings" /><published>2026-07-25T04:00:00+00:00</published><updated>2026-07-25T04:00:00+00:00</updated><id>https://motionobj.com/articles/where-mac-apps-store-data-and-settings</id><content type="html" xml:base="https://motionobj.com/articles/where-mac-apps-store-data-and-settings/"><![CDATA[<p>A Mac app is usually more than the <code class="language-plaintext highlighter-rouge">.app</code> file in Applications. Its settings, databases, documents, accounts, and caches can be spread across several folders.</p>

<p>I check the app’s own backup or migration documentation first. When the app does not document its storage, these are the places I inspect before changing anything.</p>

<p><strong>Quit the app and make a backup before moving, replacing, or deleting its files.</strong> Quit any menu bar item or helper belonging to the app too. A file that looks disposable may be the only copy of a database, licence record, or unsynced work.</p>

<h2 id="start-with-files-you-chose">Start with files you chose</h2>

<p>Documents that I create and save are not necessarily inside the app’s private data folder. They may be in:</p>

<ul>
  <li>Documents, Desktop, Downloads, or another folder I selected</li>
  <li>iCloud Drive or another sync service</li>
  <li>a folder managed by the app</li>
  <li>removable or network storage</li>
</ul>

<p>The app’s <strong>File → Open Recent</strong> menu and its settings can help identify these locations. I also check whether the app has an <strong>Export</strong>, <strong>Backup</strong>, <strong>Open Data Folder</strong>, or <strong>Reveal in Finder</strong> command. An app-provided export is usually a better backup than guessing which internal files belong together.</p>

<p>Files in iCloud need separate attention. Apple says an app can store and sync its information through iCloud when that app is enabled under <strong>System Settings → your name → iCloud</strong>. A synced copy is not the same as a versioned backup: a deletion or bad edit may sync too.</p>

<h2 id="open-your-hidden-library-folder">Open your hidden Library folder</h2>

<p>Most local support files are under the Library folder in my home folder:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library
</code></pre></div></div>

<p>The tilde means the current user’s home folder. Apple hides this Library folder in Finder.</p>

<p>To open it, switch to Finder, hold <strong>Option</strong>, and choose <strong>Go → Library</strong>. I can also choose <strong>Go → Go to Folder</strong>, enter <code class="language-plaintext highlighter-rouge">~/Library</code>, and press Return. Apple documents both methods in <a href="https://support.apple.com/guide/mac-help/mchlp1236/mac">Go directly to a specific folder on Mac</a>.</p>

<p>There are also <code class="language-plaintext highlighter-rouge">/Library</code> and <code class="language-plaintext highlighter-rouge">/System/Library</code> folders. Those have different jobs. I do not move or delete files there while looking for one user’s app settings.</p>

<h2 id="check-the-standard-library-locations">Check the standard Library locations</h2>

<p>An app can use more than one of these folders, and the folder name may be the app name, developer name, or bundle identifier such as <code class="language-plaintext highlighter-rouge">com.example.AppName</code>.</p>

<h3 id="application-support">Application Support</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library/Application Support/
</code></pre></div></div>

<p>This is the first place I check for durable local data managed by a non-sandboxed app: databases, indexes, templates, plug-ins, downloaded components, and other files the app needs to operate.</p>

<p>Apple’s file-system guidance assigns app-created support and configuration files to Application Support. The contents are app-specific, so I do not assume a folder is safe to remove just because its name is unfamiliar.</p>

<h3 id="preferences">Preferences</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library/Preferences/
</code></pre></div></div>

<p>Preferences commonly appear as property-list files with a <code class="language-plaintext highlighter-rouge">.plist</code> extension. The filename often uses the app’s bundle identifier.</p>

<p>A preferences file may contain window choices and settings, but it is rarely the app’s complete data. macOS also manages preferences while apps run, so I quit the app before copying a known preference file. I do not edit a plist merely to see what happens.</p>

<h3 id="containers">Containers</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library/Containers/
</code></pre></div></div>

<p>Sandboxed apps use app containers. Apple says macOS creates a container in <code class="language-plaintext highlighter-rouge">~/Library/Containers</code> when a sandboxed app first launches. Inside it, the app gets container-specific versions of familiar locations such as Library, Application Support, Preferences, and Caches.</p>

<p>App Sandbox is required for apps submitted to the Mac App Store. A directly downloaded app can also use App Sandbox, while another direct-download app may use the traditional Library locations. That is why the download source alone does not tell me exactly where an app stores everything.</p>

<p>Apple explains the container model in <a href="https://developer.apple.com/documentation/security/accessing-files-from-the-macos-app-sandbox">Accessing files from the macOS App Sandbox</a> and <a href="https://developer.apple.com/documentation/security/protecting-user-data-with-app-sandbox">Protecting user data with App Sandbox</a>.</p>

<h3 id="group-containers">Group Containers</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library/Group Containers/
</code></pre></div></div>

<p>An app group lets related apps, extensions, and helper processes share data. A main app can therefore use both its own container and one or more group containers.</p>

<p>On macOS 15 and later, Apple also protects app group containers with System Integrity Protection. Finder may ask for authorization when another app tries to access a protected container. I treat that prompt as a protection boundary, not as a reason to grant broad access without checking the folder owner. Apple describes the current protection in <a href="https://developer.apple.com/documentation/xcode/protecting-local-app-data-using-containers">Protecting local app data using containers on macOS</a>.</p>

<h3 id="caches-and-saved-state">Caches and saved state</h3>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~/Library/Caches/
~/Library/Saved Application State/
</code></pre></div></div>

<p>Caches should hold data the app can recreate or download. Saved Application State helps macOS restore windows and interface state.</p>

<p>Neither location is where I start when backing up important app data. A badly behaved app can put more in a cache than it should, but the folder name is not proof that its contents are disposable.</p>

<h2 id="passwords-and-licences-may-be-elsewhere">Passwords and licences may be elsewhere</h2>

<p>Apps can store passwords, tokens, certificates, and other secrets in Keychain rather than in their visible support folder. A licence may be tied to Keychain, an account, a receipt, the Mac App Store, the specific Mac, or a vendor’s server.</p>

<p>I do not copy random Keychain files or credential databases as part of an app-data experiment. For a new Mac, Setup Assistant or Migration Assistant and iCloud Keychain are safer starting points. The app may still require me to sign in or activate the licence again.</p>

<h2 id="one-app-can-have-several-storage-locations">One app can have several storage locations</h2>

<p>This is the practical checklist I use:</p>

<ul>
  <li>Find documents and folders I selected in the app.</li>
  <li>Check the app’s export, backup, sync, and migration documentation.</li>
  <li>Check <code class="language-plaintext highlighter-rouge">~/Library/Application Support</code> and <code class="language-plaintext highlighter-rouge">~/Library/Preferences</code>.</li>
  <li>Check <code class="language-plaintext highlighter-rouge">~/Library/Containers</code> and <code class="language-plaintext highlighter-rouge">~/Library/Group Containers</code>.</li>
  <li>Record the app version and whether it came from the App Store or the developer.</li>
  <li>Keep caches, credentials, licences, and cloud data as separate questions.</li>
</ul>

<p>Apple’s <a href="https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/">File System Programming Guide</a> explains why apps use different standard locations and why sandboxed paths behave differently.</p>

<p>Finding the folders is only the inventory step. I use that inventory to <a href="/articles/back-up-restore-mac-app-settings-local-data/">back up and restore the app’s settings and local data</a> without pretending that one copied folder is a complete backup.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Find a Mac app's local data and settings in Application Support, Preferences, sandbox containers, app groups, documents, and synced storage.]]></summary></entry><entry><title type="html">How to Transcribe a Zoom Recording Locally on Mac Without Uploading It</title><link href="https://motionobj.com/articles/transcribe-zoom-recording-locally-on-mac/" rel="alternate" type="text/html" title="How to Transcribe a Zoom Recording Locally on Mac Without Uploading It" /><published>2026-07-25T03:00:00+00:00</published><updated>2026-07-25T03:00:00+00:00</updated><id>https://motionobj.com/articles/transcribe-zoom-recording-locally-on-mac</id><content type="html" xml:base="https://motionobj.com/articles/transcribe-zoom-recording-locally-on-mac/"><![CDATA[<style>
  .post-meta,
  .site-footer,
  .site-footer .footer-col-wrapper {
    color: #595f67;
  }

  .post-content a,
  .site-footer a {
    color: #155a9f;
  }

  .post-content .mf-actions {
    margin-top: 2rem;
    padding: 1.5rem;
    border-left: 4px solid #b32028;
    background: #f3f1ed;
  }

  .post-content .mf-actions p:last-child {
    margin-bottom: 0;
  }

  .post-content .zoom-purchase-link {
    display: inline-flex;
    min-height: 44px;
    align-items: center;
    padding: 0 18px;
    border-radius: 4px;
    background: #17191c;
    color: #fff;
    font-weight: 600;
    text-decoration: none;
  }

  .post-content .zoom-purchase-link:focus-visible {
    outline: 3px solid #b32028;
    outline-offset: 3px;
  }
</style>

<p>If a Zoom meeting is already over, I do not need another bot joining the next meeting. I need the recording file that Zoom already made, a local transcript, and a way to find the meeting again later.</p>

<p>My workflow is to locate or download the completed Zoom recording, put its files in one folder, then open that folder in <a href="/minutefile/">MinuteFile for Mac</a>. MinuteFile transcribes the recording on the Mac and keeps the recording and editable transcript together.</p>

<h2 id="find-a-zoom-recording-saved-on-your-mac">Find a Zoom recording saved on your Mac</h2>

<p>Zoom computer recordings are stored on the Mac that recorded the meeting. The default folder is:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/Users/your-name/Documents/Zoom
</code></pre></div></div>

<p>Zoom may be using a different folder. In the Zoom Workplace app, open <strong>Settings</strong>, choose <strong>Recording</strong>, then check <strong>Local recording storage</strong>. Click <strong>Open</strong> beside the storage location to reveal the folder in Finder.</p>

<p>Zoom also lists computer recordings in the app:</p>

<ol>
  <li>Open <strong>Home</strong> and click <strong>Open recordings</strong>.</li>
  <li>In <strong>My files → Meeting recordings</strong>, choose <strong>Computer recordings</strong>.</li>
  <li>Open the menu for the completed meeting and click <strong>View file location</strong>.</li>
</ol>

<p>If Zoom shows <strong>Convert</strong> instead, let it finish converting the recording first. A completed computer recording commonly includes an MP4 video, an M4A audio file, and a chat text file, depending on the meeting and recording settings.</p>

<p>Zoom documents the current steps in <a href="https://support.zoom.com/hc/en/article?id=zm_kb&amp;onlycontent=1&amp;platform=mac&amp;product=zoom&amp;sysparm_article=KB0063423">Managing computer recordings</a>.</p>

<h2 id="download-a-completed-zoom-cloud-recording">Download a completed Zoom cloud recording</h2>

<p>A cloud recording is not on the Mac until it is downloaded.</p>

<ol>
  <li>Sign in to the Zoom web portal.</li>
  <li>Open <strong>Recordings &amp; Transcripts</strong>, then <strong>Cloud recordings</strong>.</li>
  <li>Open the processed recording.</li>
  <li>Click <strong>Download</strong> and confirm.</li>
</ol>

<p>The recording owner or an authorised user must have download access. If the recording is still processing, wait for Zoom to finish before downloading it. Zoom documents the permissions and steps in <a href="https://support.zoom.com/hc/en/article?id=zm_kb&amp;sysparm_article=KB0067567">Managing and sharing cloud recordings</a>.</p>

<p>I put the downloaded files for one meeting in their own folder. Keeping the MP4 or M4A beside any VTT, TXT, or chat files makes the archive easier to inspect later.</p>

<h2 id="bring-the-completed-recording-into-minutefile">Bring the completed recording into MinuteFile</h2>

<p>Open MinuteFile and choose either the individual meeting folder or a parent folder containing several completed recordings. For Zoom computer recordings, that parent folder can be <code class="language-plaintext highlighter-rouge">~/Documents/Zoom</code>.</p>

<p>MinuteFile detects recording folders and their audio, video, caption, and chat files. Select the meeting, choose the transcription model and language offered by the app, then start transcription. The first use of a model may download it from its model host.</p>

<p>Once the required model is installed, MinuteFile runs transcription on the Mac. The recording and transcript are not uploaded to a MotionObj cloud transcription service.</p>

<p>MinuteFile starts after the recording exists. It does not capture the live Zoom meeting, join as a bot, or create a cloud summary.</p>

<h2 id="if-the-recording-does-not-appear">If the recording does not appear</h2>

<p>Two checks cover most missing Zoom recordings.</p>

<h3 id="check-whether-zoom-finished-the-recording">Check whether Zoom finished the recording</h3>

<p>A computer recording may still need conversion after the meeting ends. Open <strong>Computer recordings</strong> in Zoom and click <strong>Convert</strong> if that action is shown. Import the recording after Zoom finishes conversion and opens the recording location.</p>

<p>For a cloud recording, check that Zoom has finished processing it and that the recording owner allows downloads. A shared playback link does not always include permission to download the files.</p>

<h3 id="keep-each-downloaded-meeting-in-one-folder">Keep each downloaded meeting in one folder</h3>

<p>MinuteFile treats a folder as the meeting record. Keep the recording media and any matching caption, transcript, or chat files together. If a cloud download places several files loose in <code class="language-plaintext highlighter-rouge">Downloads</code>, move the files for that meeting into one folder before importing it.</p>

<p>When both audio and video are present, MinuteFile chooses a usable transcription source from the files it detects. There is no need to extract audio from the MP4 first. Keeping the original files also means I can open the source recording again while reviewing the transcript.</p>

<h2 id="use-an-existing-zoom-transcript-when-you-already-have-one">Use an existing Zoom transcript when you already have one</h2>

<p>MinuteFile 0.1.6 can also turn an existing VTT, SRT, or TXT transcript into the editable archive transcript without transcribing the audio again.</p>

<p>Keep the transcript file in the meeting folder, select the recording in MinuteFile, then choose the existing transcript. MinuteFile keeps a copy of the source as a Supporting File and labels it as not generated by MinuteFile. Recognised VTT or SRT timestamps remain connected to local playback; plain TXT stays editable and searchable but cannot provide timestamp seeking that was not in the source.</p>

<h2 id="review-the-transcript-and-keep-the-meeting-searchable">Review the transcript and keep the meeting searchable</h2>

<p>Transcription is not the last step. I play the local recording against the transcript, correct text and speaker labels, and add bookmarks to moments I need to revisit. Transcripts and speaker labels can contain errors, so I review anything I plan to publish or treat as a record.</p>

<p>MinuteFile keeps saved transcripts in a searchable archive on the Mac. I can search across meetings, jump from timestamps to local playback, and export TXT, Markdown, or HTML copies.</p>

<p>I keep the original Zoom folder and exported transcripts backed up separately. I also make sure I am allowed to keep and process the recording; the local workflow does not change recording consent or access rules.</p>

<p>The app still uses the network for optional model downloads, signed update checks and downloads, and Stripe checkout. <a href="/minutefile/privacy/">MinuteFile’s privacy page</a> describes those boundaries.</p>

<div id="try-minutefile" class="mf-actions">
  <p><a href="/minutefile/MinuteFile-latest.zip">Try MinuteFile on three recordings free</a> or <a href="/minutefile/">see the MinuteFile workflow and licence details</a>. A perpetual licence costs US$39 paid once.</p>

  <p><a class="zoom-purchase-link" href="https://buy.stripe.com/8x214n29O4fAcBu3Kx3wQ03?client_reference_id=minutefile_zoom_recording_article">Buy MinuteFile for US$39</a></p>
</div>]]></content><author><name></name></author><summary type="html"><![CDATA[Find a completed Zoom recording on your Mac, transcribe it locally, and keep the recording and editable transcript in a searchable archive.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/minutefile/transcript.webp" /><media:content medium="image" url="https://motionobj.com/images/minutefile/transcript.webp" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Regex Performance Tester</title><link href="https://motionobj.com/articles/regex-performance-tester/" rel="alternate" type="text/html" title="Regex Performance Tester" /><published>2026-06-24T07:20:00+00:00</published><updated>2026-06-24T07:20:00+00:00</updated><id>https://motionobj.com/articles/regex-performance-tester</id><content type="html" xml:base="https://motionobj.com/articles/regex-performance-tester/"><![CDATA[<p>Most regular expressions are fast enough. The ones that are not usually fail in a boring way: they work on small input and then get slow when the input is longer or almost matches.</p>

<p>I test for that before using a regex on untrusted or large input.</p>

<h2 id="the-pattern-i-watch-for">The pattern I watch for</h2>

<p>The classic problem is nested repetition:</p>

<pre><code class="language-regex">^(a+)+$
</code></pre>

<p>The pattern looks small. It can get expensive on input that almost matches:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
</code></pre></div></div>

<p>The engine tries many ways to split the <code class="language-plaintext highlighter-rouge">a</code> characters across the nested groups before it gives up.</p>

<p>I do not need a benchmark for every regex. I do need to pause when I see repetition inside repetition, especially if the input can be long.</p>

<h2 id="make-the-regex-more-specific">Make the regex more specific</h2>

<p>The first fix is usually to make the pattern less vague.</p>

<p>Instead of:</p>

<pre><code class="language-regex">^(.+)+$
</code></pre>

<p>I look for something closer to the input I expect:</p>

<pre><code class="language-regex">^[A-Za-z0-9_-]+$
</code></pre>

<p>Instead of matching “anything”, match the characters that are valid.</p>

<h2 id="use-anchors-when-the-whole-string-should-match">Use anchors when the whole string should match</h2>

<p>If the whole string must match, I anchor it:</p>

<pre><code class="language-regex">^[A-Z]+-[0-9]+$
</code></pre>

<p>Without anchors, the engine can search around inside a string. That may be correct. It may also be unnecessary work.</p>

<h2 id="test-with-bad-input">Test with bad input</h2>

<p>I test with:</p>

<ul>
  <li>valid short input</li>
  <li>valid long input</li>
  <li>invalid input that fails quickly</li>
  <li>invalid input that almost matches</li>
  <li>empty input</li>
</ul>

<p>The fourth case matters. Many slow regex problems show up when the input is almost valid.</p>

<h2 id="keep-the-target-engine-in-mind">Keep the target engine in mind</h2>

<p>Regex performance depends on the engine. JavaScript, Swift, Ruby, nginx, <code class="language-plaintext highlighter-rouge">grep</code>, and <code class="language-plaintext highlighter-rouge">sed</code> do not all behave the same way.</p>

<p>I use <a href="/regex/">Regex for macOS</a> for the first pass. It is useful for building the expression and checking matches. If the pattern will run in a server, CLI tool, or app hot path, I also test it where it will run.</p>

<h2 id="a-small-timing-check">A small timing check</h2>

<p>For a quick command-line check, I use the target language and a sample input.</p>

<p>Ruby example:</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">require</span> <span class="s2">"benchmark"</span>

<span class="n">pattern</span> <span class="o">=</span> <span class="sr">/\A[A-Za-z0-9_-]+\z/</span>
<span class="n">input</span> <span class="o">=</span> <span class="s2">"a"</span> <span class="o">*</span> <span class="mi">10_000</span>

<span class="nb">puts</span> <span class="no">Benchmark</span><span class="p">.</span><span class="nf">measure</span> <span class="p">{</span>
  <span class="mi">1_000</span><span class="p">.</span><span class="nf">times</span> <span class="p">{</span> <span class="n">pattern</span><span class="p">.</span><span class="nf">match?</span><span class="p">(</span><span class="n">input</span><span class="p">)</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The script is a cheap way to catch obviously bad patterns. I still test the final code path if the regex matters.</p>

<h2 id="my-regex-performance-checklist">My regex performance checklist</h2>

<p>Before I use a regex on large or untrusted input, I check:</p>

<ul>
  <li>no nested repetition unless I have a good reason</li>
  <li>specific character classes instead of <code class="language-plaintext highlighter-rouge">.*</code> everywhere</li>
  <li>anchors when I need a whole-string match</li>
  <li>clear maximum lengths where the app can enforce them</li>
  <li>bad input that almost matches</li>
  <li>the actual engine that will run the regex</li>
</ul>

<p>If the pattern is hard to reason about, I simplify it or replace it with parsing code.</p>

<p>You can get <a href="https://apps.apple.com/us/app/regex-tester-builder/id422501241?mt=12">Regex Tester/Builder on the Mac App Store</a>.</p>

<p>Related: <a href="/articles/regex-tester-for-macos/">Regex tester for macOS</a> and <a href="/articles/nginx-regex-tester/">nginx regex tester</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A practical checklist for testing regular expression performance and avoiding slow patterns before they hit production input.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/regex/device.png" /><media:content medium="image" url="https://motionobj.com/images/regex/device.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">sed Regex Tester</title><link href="https://motionobj.com/articles/sed-regex-tester/" rel="alternate" type="text/html" title="sed Regex Tester" /><published>2026-06-24T07:15:00+00:00</published><updated>2026-06-24T07:15:00+00:00</updated><id>https://motionobj.com/articles/sed-regex-tester</id><content type="html" xml:base="https://motionobj.com/articles/sed-regex-tester/"><![CDATA[<p><code class="language-plaintext highlighter-rouge">sed</code> is one of those tools where the regex is only half the problem. The rest is shell quoting and replacement syntax.</p>

<p>I still test the regular expression separately first. Then I put it into <code class="language-plaintext highlighter-rouge">sed</code>.</p>

<h2 id="use-extended-regexes-on-macos">Use extended regexes on macOS</h2>

<p>On macOS, I usually use <code class="language-plaintext highlighter-rouge">sed -E</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s/old/new/g'</span> file.txt
</code></pre></div></div>

<p>That enables extended regular expressions. It keeps patterns easier to read because I do not need to escape common grouping and alternation syntax as much.</p>

<p>Example input:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AUTH-1284 fixed
REGEX-42 needs review
BILLING-9001 shipped
</code></pre></div></div>

<p>Pattern:</p>

<pre><code class="language-regex">([A-Z]+)-([0-9]+)
</code></pre>

<p>Replacement:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>\1 ticket \2
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">sed</code> command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s/([A-Z]+)-([0-9]+)/\1 ticket \2/g'</span> tickets.txt
</code></pre></div></div>

<p>Result:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AUTH ticket 1284 fixed
REGEX ticket 42 needs review
BILLING ticket 9001 shipped
</code></pre></div></div>

<h2 id="test-the-match-and-the-replacement-separately">Test the match and the replacement separately</h2>

<p>When I am working on a <code class="language-plaintext highlighter-rouge">sed</code> command, I split the problem:</p>

<ul>
  <li>Test the regex against sample text.</li>
  <li>Check the capture groups.</li>
  <li>Then write the replacement string.</li>
</ul>

<p>This avoids the usual “why did <code class="language-plaintext highlighter-rouge">sed</code> replace the wrong thing?” loop.</p>

<p><a href="/regex/">Regex for macOS</a> helps with the first two steps. It shows the matches and capture groups while I edit the pattern.</p>

<p>One macOS <code class="language-plaintext highlighter-rouge">sed</code> detail to watch: I do not use <code class="language-plaintext highlighter-rouge">\b</code> there as a word-boundary shortcut. If I need strict boundaries in <code class="language-plaintext highlighter-rouge">sed</code>, I test that exact <code class="language-plaintext highlighter-rouge">sed</code> expression instead of assuming it behaves like Swift, JavaScript, or Ruby.</p>

<h2 id="watch-out-for-shell-quoting">Watch out for shell quoting</h2>

<p>The pattern that works in a regex tester may need quoting changes in Terminal.</p>

<p>I normally wrap the <code class="language-plaintext highlighter-rouge">sed</code> expression in single quotes:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s/foo/bar/g'</span> file.txt
</code></pre></div></div>

<p>If the replacement needs a literal single quote, I stop and make the command easier to read. Sometimes that means using a small Ruby, Python, or Perl script instead of turning the shell command into punctuation soup.</p>

<h2 id="sed-is-not-a-parser">sed is not a parser</h2>

<p><code class="language-plaintext highlighter-rouge">sed</code> is great for line-oriented text changes:</p>

<ul>
  <li>renaming simple tokens</li>
  <li>changing config values</li>
  <li>cleaning generated output</li>
  <li>quick one-off migrations</li>
</ul>

<p>It is not what I use for structured formats when a parser is available. For JSON, HTML, XML, and non-trivial CSV, I use a proper parser.</p>

<h2 id="my-sed-regex-checklist">My sed regex checklist</h2>

<p>Before I run a destructive command, I check:</p>

<ul>
  <li>Does the regex match only the lines I want?</li>
  <li>Are capture groups in the right order?</li>
  <li>Does the replacement preserve the parts I need?</li>
  <li>Have I tested on a copy or printed output first?</li>
  <li>Do I need <code class="language-plaintext highlighter-rouge">-E</code>?</li>
  <li>Is <code class="language-plaintext highlighter-rouge">sed</code> still the right tool?</li>
</ul>

<p>You can get <a href="https://apps.apple.com/us/app/regex-tester-builder/id422501241?mt=12">Regex Tester/Builder on the Mac App Store</a>.</p>

<p>Related: <a href="/articles/regex-tester-for-macos/">Regex tester for macOS</a> and <a href="/articles/swift-regex-builder/">Swift Regex Builder</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[How I test sed regular expressions on macOS, including extended regexes, capture groups, and replacement strings.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/regex/device.png" /><media:content medium="image" url="https://motionobj.com/images/regex/device.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">nginx Regex Tester</title><link href="https://motionobj.com/articles/nginx-regex-tester/" rel="alternate" type="text/html" title="nginx Regex Tester" /><published>2026-06-24T07:10:00+00:00</published><updated>2026-06-24T07:10:00+00:00</updated><id>https://motionobj.com/articles/nginx-regex-tester</id><content type="html" xml:base="https://motionobj.com/articles/nginx-regex-tester/"><![CDATA[<p>I do not like editing nginx regexes directly in production config. A small mistake in a <code class="language-plaintext highlighter-rouge">location</code> or <code class="language-plaintext highlighter-rouge">rewrite</code> rule can send the wrong traffic to the wrong place.</p>

<p>I test the pattern first, then put it into nginx.</p>

<h2 id="nginx-regex-locations">nginx regex locations</h2>

<p>nginx has a few location forms. The two regex forms I use are:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">location</span> <span class="p">~</span> <span class="sr">^/articles/(.+)/$</span> <span class="p">{</span>
    <span class="c1"># case-sensitive regex match</span>
<span class="p">}</span>

<span class="k">location</span> <span class="p">~</span><span class="sr">*</span> <span class="err">\</span><span class="s">.(png|jpg|jpeg|gif|webp)</span>$ <span class="p">{</span>
    <span class="c1"># case-insensitive regex match</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The important bits:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">~</code> is case-sensitive.</li>
  <li><code class="language-plaintext highlighter-rouge">~*</code> is case-insensitive.</li>
  <li>Captures are available as <code class="language-plaintext highlighter-rouge">$1</code>, <code class="language-plaintext highlighter-rouge">$2</code>, and so on.</li>
  <li>nginx chooses locations with its own matching rules. Prefix locations matter, and regex locations are tested in order when nginx gets to that step.</li>
</ul>

<p>That last part is where testing the regex alone is not enough. I still test nginx config with nginx. But testing the expression first catches most of the obvious mistakes.</p>

<h2 id="test-the-path-not-the-full-url">Test the path, not the full URL</h2>

<p>For nginx <code class="language-plaintext highlighter-rouge">location</code> blocks, I usually test the path:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/articles/regex-macos-tutorial/
/articles/swift-regex-builder/
/regex/
/images/regex/device.png
</code></pre></div></div>

<p>Then I write a pattern:</p>

<pre><code class="language-regex">^/articles/([^/]+)/$
</code></pre>

<p>This captures:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>regex-macos-tutorial
swift-regex-builder
</code></pre></div></div>

<p>It does not match:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/regex/
/images/regex/device.png
</code></pre></div></div>

<p>That is the kind of quick check I want before touching a config file.</p>

<h2 id="test-rewrite-captures">Test rewrite captures</h2>

<p>For a routing rule, I test the capture groups before I write the nginx rule.</p>

<p>Pattern:</p>

<pre><code class="language-regex">^/old/articles/(.+)/$
</code></pre>

<p>Replacement target:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/articles/$1/
</code></pre></div></div>

<p>nginx rule:</p>

<div class="language-nginx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">rewrite</span> <span class="s">^/old/articles/(.+)/</span>$ <span class="n">/articles/</span><span class="nv">$1</span><span class="n">/</span> <span class="s">permanent</span><span class="p">;</span>
</code></pre></div></div>

<p>If the regex tester shows the capture includes a trailing slash I did not expect, I fix it before it becomes a rewrite bug.</p>

<h2 id="check-nginx-syntax-too">Check nginx syntax too</h2>

<p>After editing config, I still run:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nginx <span class="nt">-t</span>
</code></pre></div></div>

<p>or, inside Docker:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker <span class="nb">exec </span>nginx nginx <span class="nt">-t</span>
</code></pre></div></div>

<p>The regex tester checks the expression. <code class="language-plaintext highlighter-rouge">nginx -t</code> checks whether nginx accepts the config. I want both.</p>

<h2 id="where-regex-for-macos-fits">Where Regex for macOS fits</h2>

<p><a href="/regex/">Regex for macOS</a> is useful for the first pass: sample paths on one side, pattern on the other, matches and capture groups visible while I edit.</p>

<p>Then I move the pattern into nginx config and test the config normally.</p>

<p>You can get <a href="https://apps.apple.com/us/app/regex-tester-builder/id422501241?mt=12">Regex Tester/Builder on the Mac App Store</a>.</p>

<p>Related: <a href="/articles/regex-tester-for-macos/">Regex tester for macOS</a> and <a href="/articles/regex-performance-tester/">regex performance tester</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[How I test nginx regular expressions for location blocks, rewrites, captures, and routing rules before changing server config.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/regex/device.png" /><media:content medium="image" url="https://motionobj.com/images/regex/device.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Swift Regex Builder</title><link href="https://motionobj.com/articles/swift-regex-builder/" rel="alternate" type="text/html" title="Swift Regex Builder" /><published>2026-06-24T07:05:00+00:00</published><updated>2026-06-24T07:05:00+00:00</updated><id>https://motionobj.com/articles/swift-regex-builder</id><content type="html" xml:base="https://motionobj.com/articles/swift-regex-builder/"><![CDATA[<p>Swift has good regular expression support, but I still like to test the pattern outside the code first. It is faster to change sample text and inspect matches in a small Mac app than to keep rebuilding while I am still figuring out the expression.</p>

<p>The workflow I use is boring: test the regex, make the capture groups obvious, then move it into Swift.</p>

<p>Swift also has a <code class="language-plaintext highlighter-rouge">RegexBuilder</code> DSL for building regular expressions in code. That is useful when I want the expression to read more like Swift. I still start with the plain regex when I am moving between tools, because it is easier to test the same pattern in a Mac app, a shell command, and a code snippet.</p>

<h2 id="start-with-the-plain-regex">Start with the plain regex</h2>

<p>Say I want to match a simple issue key:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AUTH-1284
REGEX-42
BILLING-9001
</code></pre></div></div>

<p>The plain regex is:</p>

<pre><code class="language-regex">\b([A-Z]+)-(\d+)\b
</code></pre>

<p>Before I put this in Swift, I want to know two things:</p>

<ul>
  <li>The full match is the whole issue key.</li>
  <li>Group 1 is the project key, and group 2 is the number.</li>
</ul>

<p>That is what I test in <a href="/regex/">Regex for macOS</a>. The app lets me keep the sample text and the expression together while I work.</p>

<h2 id="move-it-into-swift">Move it into Swift</h2>

<p>In Swift, a raw string keeps the regex readable:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">pattern</span> <span class="o">=</span> <span class="err">#</span><span class="s">"</span><span class="err">\</span><span class="s">b([A-Z]+)-(</span><span class="err">\</span><span class="s">d+)</span><span class="err">\</span><span class="s">b"</span><span class="err">#</span>
</code></pre></div></div>

<p>If I am using <code class="language-plaintext highlighter-rouge">NSRegularExpression</code>, the code looks like this:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">import</span> <span class="kt">Foundation</span>

<span class="k">let</span> <span class="nv">text</span> <span class="o">=</span> <span class="s">"Fixed AUTH-1284 and REGEX-42."</span>
<span class="k">let</span> <span class="nv">regex</span> <span class="o">=</span> <span class="k">try</span> <span class="kt">NSRegularExpression</span><span class="p">(</span><span class="nv">pattern</span><span class="p">:</span> <span class="err">#</span><span class="s">"</span><span class="err">\</span><span class="s">b([A-Z]+)-(</span><span class="err">\</span><span class="s">d+)</span><span class="err">\</span><span class="s">b"</span><span class="err">#</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">range</span> <span class="o">=</span> <span class="kt">NSRange</span><span class="p">(</span><span class="n">text</span><span class="o">.</span><span class="n">startIndex</span><span class="o">..&lt;</span><span class="n">text</span><span class="o">.</span><span class="n">endIndex</span><span class="p">,</span> <span class="nv">in</span><span class="p">:</span> <span class="n">text</span><span class="p">)</span>

<span class="k">let</span> <span class="nv">matches</span> <span class="o">=</span> <span class="n">regex</span><span class="o">.</span><span class="nf">matches</span><span class="p">(</span><span class="nv">in</span><span class="p">:</span> <span class="n">text</span><span class="p">,</span> <span class="nv">range</span><span class="p">:</span> <span class="n">range</span><span class="p">)</span>
<span class="k">for</span> <span class="n">match</span> <span class="k">in</span> <span class="n">matches</span> <span class="p">{</span>
    <span class="k">let</span> <span class="nv">fullRange</span> <span class="o">=</span> <span class="kt">Range</span><span class="p">(</span><span class="n">match</span><span class="o">.</span><span class="nf">range</span><span class="p">(</span><span class="nv">at</span><span class="p">:</span> <span class="mi">0</span><span class="p">),</span> <span class="nv">in</span><span class="p">:</span> <span class="n">text</span><span class="p">)</span><span class="o">!</span>
    <span class="nf">print</span><span class="p">(</span><span class="n">text</span><span class="p">[</span><span class="n">fullRange</span><span class="p">])</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In production code I would handle failed range conversions instead of force-unwrapping. This example keeps the snippet focused.</p>

<p>If I am building a larger parser in Swift, I would look at <code class="language-plaintext highlighter-rouge">RegexBuilder</code> too. For small patterns I expect to copy between Swift, Terminal, nginx notes, or documentation, the plain regex is still the most portable starting point.</p>

<p>That is the distinction I care about: <code class="language-plaintext highlighter-rouge">RegexBuilder</code> can make Swift code clearer, but it is not the only place to test the matching rule. I still want sample input, visible captures, and a quick way to catch mistakes before I decide how the final Swift code should look.</p>

<h2 id="check-escaping-separately">Check escaping separately</h2>

<p>Escaping is where I make mistakes.</p>

<p>There are a few layers:</p>

<ul>
  <li>regex escaping</li>
  <li>Swift string escaping</li>
  <li>replacement string escaping, if I am replacing text</li>
</ul>

<p>Raw strings help:</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">emailPattern</span> <span class="o">=</span> <span class="err">#</span><span class="s">"[</span><span class="err">\</span><span class="s">w.%+-]+@[</span><span class="err">\</span><span class="s">w.-]+</span><span class="err">\</span><span class="s">.[A-Za-z]{2,}"</span><span class="err">#</span>
</code></pre></div></div>

<p>That is easier to read than doubling backslashes everywhere.</p>

<h2 id="when-i-would-not-use-a-fancy-regex">When I would not use a fancy regex</h2>

<p>For simple string work, I do not force everything into a regular expression. If a prefix check, suffix check, split, or parser is clearer, I use that.</p>

<p>Regex is good when the input is text-like and the rule is compact. It gets worse when the input is structured data pretending to be text. HTML, JSON, and CSV usually deserve a parser.</p>

<h2 id="my-swift-regex-checklist">My Swift regex checklist</h2>

<p>Before I paste a pattern into Swift, I check:</p>

<ul>
  <li>sample strings that should match</li>
  <li>sample strings that should not match</li>
  <li>capture group order</li>
  <li>Unicode assumptions</li>
  <li>whether I need multiline or case-insensitive options</li>
  <li>whether a parser would be clearer</li>
</ul>

<p>If I need to iterate on the pattern, I do it in <a href="/regex/">Regex for macOS</a> first, then copy the result into Swift.</p>

<p>You can get <a href="https://apps.apple.com/us/app/regex-tester-builder/id422501241?mt=12">Regex Tester/Builder on the Mac App Store</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[How I think about building and testing Swift regular expressions on macOS before moving the pattern into code.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/regex/device.png" /><media:content medium="image" url="https://motionobj.com/images/regex/device.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Regex Tester for macOS</title><link href="https://motionobj.com/articles/regex-tester-for-macos/" rel="alternate" type="text/html" title="Regex Tester for macOS" /><published>2026-06-24T07:00:00+00:00</published><updated>2026-06-24T07:00:00+00:00</updated><id>https://motionobj.com/articles/regex-tester-for-macos</id><content type="html" xml:base="https://motionobj.com/articles/regex-tester-for-macos/"><![CDATA[<p>I usually test regular expressions before I paste them into code. That sounds obvious, but it still saves me from small mistakes — wrong escaping, missing capture groups, and patterns that work in one place but not another.</p>

<p>My preference on the Mac is simple: test the pattern against real sample text, then copy it into the tool that needs it.</p>

<h2 id="why-use-a-mac-regex-tester">Why use a Mac regex tester</h2>

<p>A regular expression is rarely just the pattern. It usually comes with a few details attached:</p>

<ul>
  <li>sample input</li>
  <li>match options such as case-insensitive or multiline matching</li>
  <li>capture groups</li>
  <li>the replacement string, if I am doing a search-and-replace</li>
  <li>the engine or tool that will run it</li>
</ul>

<p>That last one matters. A regex that works in JavaScript may need changes before it works in <code class="language-plaintext highlighter-rouge">grep</code>, <code class="language-plaintext highlighter-rouge">sed</code>, Swift, nginx, or Ruby.</p>

<p><a href="/regex/">Regex for macOS</a> is useful when I want a focused place to edit the pattern and sample text side by side. I can see the matches, inspect capture groups, and copy the final pattern into code or Terminal.</p>

<h2 id="a-small-example">A small example</h2>

<p>Say I want to pull ticket IDs out of text like this:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Fixed AUTH-1284 and REGEX-42.
QA needs to check BILLING-9001.
</code></pre></div></div>

<p>I would start with:</p>

<pre><code class="language-regex">\b[A-Z]+-\d+\b
</code></pre>

<p>That matches:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AUTH-1284
REGEX-42
BILLING-9001
</code></pre></div></div>

<p>Then I decide whether I need a capture group:</p>

<pre><code class="language-regex">\b([A-Z]+)-(\d+)\b
</code></pre>

<p>Now I can inspect the project key and number separately:</p>

<ul>
  <li>Group 1: <code class="language-plaintext highlighter-rouge">AUTH</code>, <code class="language-plaintext highlighter-rouge">REGEX</code>, <code class="language-plaintext highlighter-rouge">BILLING</code></li>
  <li>Group 2: <code class="language-plaintext highlighter-rouge">1284</code>, <code class="language-plaintext highlighter-rouge">42</code>, <code class="language-plaintext highlighter-rouge">9001</code></li>
</ul>

<p>That is the point of using a tester. I do not want to guess whether group 1 is what I think it is.</p>

<h2 id="write-down-the-cases-before-tweaking-the-regex">Write down the cases before tweaking the regex</h2>

<p>The fastest way I know to waste time with regex is to keep changing the pattern without writing down what should match.</p>

<p>I usually make a tiny test set first:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AUTH-1284        yes
REGEX-42         yes
BILLING-9001     yes
AUTH-            no
abc-123          no, if project keys must be uppercase
AUTH-1284-extra  no, if the whole token should match
</code></pre></div></div>

<p>Then I adjust the expression until the matches line up with those cases.</p>

<p>This is more useful than staring at the regex and trying to reason it out in my head. It also catches the mistakes that do not look like mistakes at first: a missing anchor, a capture group in the wrong place, or a pattern that matches part of a longer token.</p>

<h2 id="taking-it-to-terminal">Taking it to Terminal</h2>

<p>On macOS, I usually start with <code class="language-plaintext highlighter-rouge">grep -E</code> when I need extended regular expressions:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep</span> <span class="nt">-E</span> <span class="s1">'\b[A-Z]+-[0-9]+\b'</span> tickets.txt
</code></pre></div></div>

<p>For replacement work, I usually reach for <code class="language-plaintext highlighter-rouge">sed -E</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s/([A-Z]+)-([0-9]+)/\1 ticket \2/g'</span> tickets.txt
</code></pre></div></div>

<p>The pattern is close to the one I tested. Shell quoting and the regex engine both matter, so I still check the command before using it on real files. For example, macOS <code class="language-plaintext highlighter-rouge">sed</code> does not treat <code class="language-plaintext highlighter-rouge">\b</code> as the same word-boundary token that many programming-language regex engines do.</p>

<h2 id="what-i-check-before-using-a-regex">What I check before using a regex</h2>

<p>The short checklist:</p>

<ul>
  <li>Does it match the examples I expect?</li>
  <li>Does it avoid examples I do not want?</li>
  <li>Are the capture groups in the right order?</li>
  <li>Does it still work when the input has multiple lines?</li>
  <li>Do I need a case-insensitive option instead of writing <code class="language-plaintext highlighter-rouge">[A-Za-z]</code> everywhere?</li>
  <li>Does the destination tool support the features I used?</li>
</ul>

<p>Lookahead, lookbehind, and backreferences are useful, but they are also where portability starts to get worse. I use them when the target supports them and keep the pattern simpler when it does not.</p>

<h2 id="when-i-use-regex-for-macos">When I use Regex for macOS</h2>

<p>I use <a href="/regex/">Regex for macOS</a> when I want a native app instead of another browser tab. It does one job: edit and test regular expressions on the Mac.</p>

<p>I mostly want a focused place to work through the pattern, confirm the matches, and copy it into the next thing.</p>

<p>You can get <a href="https://apps.apple.com/us/app/regex-tester-builder/id422501241?mt=12">Regex Tester/Builder on the Mac App Store</a>.</p>

<p>Related: <a href="/articles/swift-regex-builder/">Swift Regex Builder</a>, <a href="/articles/nginx-regex-tester/">nginx regex tester</a>, and <a href="/articles/sed-regex-tester/">sed regex tester</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[A practical way to test regular expressions on macOS before using them in code, Terminal, grep, sed, nginx, or another app.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/regex/device.png" /><media:content medium="image" url="https://motionobj.com/images/regex/device.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Reducing Disk Usage on Your Mac with CleanMyMac</title><link href="https://motionobj.com/articles/reducing-disk-usage-on-your-mac-with-cleanmymac/" rel="alternate" type="text/html" title="Reducing Disk Usage on Your Mac with CleanMyMac" /><published>2014-02-22T08:37:00+00:00</published><updated>2014-02-22T08:37:00+00:00</updated><id>https://motionobj.com/articles/reducing-disk-usage-on-your-mac-with-cleanmymac</id><content type="html" xml:base="https://motionobj.com/articles/reducing-disk-usage-on-your-mac-with-cleanmymac/"><![CDATA[<p style="background-color: #fff066; padding: 14px;">
(I released during a long period where OmniDiskSweeper wasn't available, it is, again), so if you'd like to try my take on this, check out <a href="/simplydisksweeper/">SimplyDiskSweeper</a>
</p>

<p>This is the third article of a series of articles on reducing disk space usage on your Mac. Read the first post: <a href="/articles/reducing-disk-usage-on-your-mac-by-processing-your-videos/">Reducing Disk Usage on Your Mac by Processing Your Videos</a> and second post: <a href="/articles/reducing-disk-usage-on-your-mac-with-omnidisksweeper/">Reducing Disk Usage on Your Mac with OmniDiskSweeper</a> if you haven’t.</p>

<p>In our <a href="/articles/reducing-disk-usage-on-your-mac-with-omnidisksweeper/">second article</a>, we talked about running <a href="https://www.omnigroup.com/download/latest/OmniDiskSweeper">OmniDiskSweeper</a> and manually going through the directories and cleaning those that unnecessarily use up space. There is another utility that helps to reclaim disk space more easily – <a href="http://macpaw.com/cleanmymac">CleanMyMac</a>.</p>

<p>Note that CleanMyMac is a paid app with a free download.</p>

<h2 id="running-cleanmymac">Running CleanMyMac</h2>

<p><img src="/images/posts/cleanmymac-1.png" alt="CleanMyMac automatic cleanup screen" /></p>

<p>Once you launch the app, it’ll give you a couple of options to clean on the left bar. Make sure Automatic Cleanup is selected and click Start Over and then Scan to start.</p>

<p><img src="/images/posts/cleanmymac-2.png" alt="CleanMyMac scan result" /></p>

<p>It should take a few minutes to scan your hard disk/SSD. Once it’s done scanning, it should report how much space it can clean automatically. Careful now, DO NOT click the Clean button. Instead, look at the left bar and click on System Cleanup.</p>

<p><img src="/images/posts/cleanmymac-3.png" alt="CleanMyMac cleanup details" /></p>

<p>Click on Detail Results and it should show you a detailed breakdown of the items to will be cleaned.</p>

<p><img src="/images/posts/cleanmymac-4.png" alt="CleanMyMac selected cleanup items" /></p>

<p>As a good habit, we’ll want to only clean those items that we know will be safe without. I usually uncheck most items, including iOS Photo Cache (careful!) and check items such as iOS Software Updates that I know is safe to remove. Click Clean – it should prompt you for your password – and let it do its job.</p>

<p>Continue on with Large &amp; Old Files as well as Trash Cleanup. Happy cleaning!</p>

<p>Want more articles like this in your inbox? <a href="https://docs.google.com/forms/d/e/1FAIpQLSeo-ipHCW0RGKZqVqbQMX3vT7J_TqP3XlY9-h3V9-QgJrZceA/viewform?usp=sf_link">Join our newsletter</a> to receive free email updates, tips and tricks related to iOS &amp; macOS X.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Use CleanMyMac carefully to scan your Mac, review cleanup details, and remove files you understand instead of blindly deleting everything.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://motionobj.com/images/posts/cleanmymac-1.png" /><media:content medium="image" url="https://motionobj.com/images/posts/cleanmymac-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>