Caxton
Features Benchmarks Pricing Docs How it works Changelog Support About Download Free
Guides
All guides Large File Text Editors EmEditor for Mac UltraEdit Alternatives Notepad++ Alternatives Notepad for Mac File Too Large for VS Code CSV Editor for Mac Open a CSV File CSV Viewer for Mac Edit CSV Without Auto-Formatting Repair a Malformed CSV Remove Duplicate Rows Validate a CSV Transform a CSV Column Fixed-Width to CSV Sort a Large CSV CSV Too Big for Excel Open a Huge CSV Log Viewer for Mac View Log Files Open a 10 GB Log Filter Large Log Files Jump to a Time in a Log Find & Replace in Huge Files Find & Replace Across Files Regex Cheat Sheet Compare Two Text Files Open a SQL Dump Fix Garbled Text & Encoding Convert Line Endings Sort & Dedupe Lines Open a GBK or Big5 File Open a Large JSON File Numbers File Too Large

Find and replace with regular expressions.

A regular expression describes a shape of text instead of exact text: every line that ends in spaces, every number followed by a unit, every pair of fields in the wrong order. The same handful of forms covers nearly every find and replace you will ever do. This page lists them with examples you can paste, each tested in Caxton's find bar and, where the Terminal differs, with the grep and sed equivalents that ship on a Mac.

Download Caxton for Free · 7-day free trial of Caxton Pro, no credit card required · 7 MB · macOS 13.0+

The short answer

Every Mac has grep and sed, and both take the -E option for the extended syntax this page uses, with sed -i '' to edit a file in place. Caxton, a native Mac editor for text and data files, runs the same patterns in its find bar with the ICU engine: capture groups come back as $1 in the replacement, lookahead and lookbehind work, and every match stays within one line so an anchor means what you expect.

Which regular expression engine does Caxton use?

Caxton runs ICU regular expressions through the system's NSRegularExpression, the same engine behind most Mac and iOS apps. Three facts about it shape everything below. Patterns are evaluated one line at a time, so a match never crosses a line ending, ^ and $ mean the start and end of each line, and . never matches a line break. In the replacement, $0 is the whole match and $1 through $9 are the capture groups, with \1 reserved for backreferences inside the pattern itself. And lookahead and lookbehind, positive and negative, are part of the grammar.

In the find bar, .* turns regular expressions on, Aa sets whether case matters, and the \n toggle expands escape sequences such as \n and \t in a literal search, which is how a search crosses a line break. Edit ▸ Find ▸ Find and Replace… has the same options as a Search mode popup: Normal, Extended for the escape sequences, or Regular expression. Finding, counting and highlighting are free; Replace and Replace All change the file, so they are Caxton Pro.

The Terminal equivalents below use Apple's own grep and sed with -E, the extended syntax. Two cautions apply on a Mac. The stock sed needs -i '', with the empty quotes, to edit a file in place, and Apple's grep and sed know neither lookahead nor lookbehind nor the lazy ? suffix, so those rows carry a plain-syntax alternative instead.

How do I match the beginning or the end of a line?

PatternMatchesIn CaxtonIn grep -E and sed -E
^The start of a lineEach line's startThe same
$The end of a line, before the line breakEach line's endThe same
^$An empty lineWorks, including Replace Allgrep -Ev '^$' drops them
^#A line that starts with a hashWorksgrep -E '^#'
;$A line that ends in a semicolonWorksgrep -E ';$'

Because Caxton evaluates each line on its own, there is no multiline option to remember: the anchors always refer to the line, and a pattern that ends in $ never swallows the line break. A replacement at ^ or $ inserts text at that edge of every line, which is the whole trick behind adding a prefix or a suffix.

How do I match whitespace and trailing spaces?

PatternMatchesNote
\sOne whitespace character: a space, a tab, or a line-break characterIn sed -E write [[:space:]]; \s is not part of its grammar
\s+$Trailing spaces and tabs at the end of a lineThe everyday cleanup; see the recipes
^\s+Leading indentationReplace with nothing to flush left
\SOne character that is not whitespace[^[:space:]] in sed -E
{2,}Two or more spaces in a rowReplace with one space to collapse runs
\tA tabIn sed, press Control-V then Tab to type a literal tab, or use [[:blank:]] for a space or a tab

How do quantifiers work, and what does lazy mean?

PatternMatches
.Any single character except a line break
a*Zero or more a
a+One or more a
a?Zero or one a
a{3} · a{2,5} · a{2,}Exactly three, two to five, two or more
.*The rest of the line, as much as possible
.*?As little as possible: the lazy version

Quantifiers are greedy: <.+> on <a><b> matches the whole thing, from the first < to the last >. Appending ? makes it lazy, so <.+?> matches <a> and then <b>. Caxton accepts the lazy form. Apple's sed -E rejects it with "repetition-operator operand invalid," and grep -E is not documented to honor it, so in the Terminal write what you mean with a negated class instead: <[^>]+> matches a tag because it cannot run past the closing bracket. That form is also faster in every engine.

What are character classes?

PatternMatchesNote
[abc]One of a, b or c
[^abc]Any one character that is not a, b or cThe ^ means not only inside brackets
[a-z] · [A-Za-z0-9_]A range, or several
\dOne digit[[:digit:]] or [0-9] in sed -E
\wOne word character: a letter, a digit or an underscore[[:alnum:]_] in sed -E
\bA word boundary, with no width of its ownCaxton's boundaries are Unicode-aware; the W toggle applies the same rule to a literal search
a|bEither a or bGroup it when it is part of something longer: (cat|dog)s
\. · \( · \$A literal dot, bracket or dollar signAny special character is escaped with a backslash

How do capture groups work in the replacement?

Parentheses capture what they match, numbered from the left, and the replacement can reuse them. In Caxton write $1, $2 and so on, with $0 for the whole match. In sed -E write \1 and \2. A group you only need for grouping, not for reuse, is written (?:…) and gets no number.

FindReplace in CaxtonReplace in sed -EEffect on Smith, Jane
^(\w+), (\w+)$$2 $1\2 \1Jane Smith
(\d+)[$1][\1]Every number in brackets
^(.*)$"$1""\1"The line in quotes

Inside the pattern itself a backreference is written \1 in both engines: (\w+) \1 finds a word repeated twice in a row, such as "the the". Caxton's Find All results panel can also group matches by the $1 value, which turns a capture into a quick frequency count without replacing anything.

What are lookahead and lookbehind?

A lookaround checks what comes next or before without including it in the match, so the replacement touches only the part you captured. Caxton supports all four forms. Apple's grep and sed do not, and their -E syntax has no equivalent; for a Terminal route, capture the context and put it back with a group, which the last row shows.

PatternMeaningExample
a(?=b)a, only when b follows\d+(?= GB) matches the number in "32 GB" but not in "32 ms"
a(?!b)a, only when b does not follow^(?!#) starts a match on every line that is not a comment
(?<=b)aa, only when b comes before it(?<=\$)\d+ matches the digits of a dollar amount
(?<!b)aa, only when b does not come before it(?<!\w)\d{4}(?!\w) matches a four-digit number standing alone
In sed -ECapture the contextsed -E 's/([0-9]+) GB/\1 gigabytes/' keeps the context by writing it back

How do I match or insert a line break?

Two different jobs, with two different answers. To insert a line break, put \n in the replacement: Caxton expands it in Regular expression mode and in Extended mode, so replacing , with ,\n splits a comma-separated line into one item per line. In sed, the replacement needs a backslash followed by an actual line break, written across two lines:

sed -E 's/, /,\
/g' list.txt

To match a line break, remember that Caxton evaluates regular expressions one line at a time, so a pattern cannot reach across the break. Switch regular expressions off, turn the \n toggle on, and search for the literal text with the break written as \n: first\nsecond finds "first" at the end of one line followed by "second" at the start of the next, and a replacement of first second joins them. Pasting a selection that spans lines into the bar writes it in that form for you. The Text menu has a faster route for the common cases: Join Lines, Remove Empty Lines, and Split Lines at Delimiter…, each one undo step.

In the Terminal, sed reads one line at a time too, and joining lines is simpler with tr or paste: paste -sd ' ' file.txt joins every line with a space, and tr -d '\n' < file.txt removes the breaks outright.

How do I make a pattern case-insensitive?

In Caxton, leave the Aa toggle off and the pattern ignores case; turn it on to match exactly. ICU also accepts the inline flag (?i) at the start of a pattern. In the Terminal, grep -Ei ignores case, and Apple's sed takes an I flag after the closing delimiter: sed -E 's/error/ERROR/I'.

Recipes

Each recipe was run on a Mac with Apple's grep and sed and in Caxton's find bar with .* on. The sed forms print to the screen; add -i '' after sed to change the file in place, and keep a copy first. In Caxton, Replace All applies the whole recipe as one undo step, so ⌘Z brings the file back.

Remove trailing spaces

Find:     \s+$
Replace:  (nothing)

sed -E 's/[[:space:]]+$//' file.txt

Every line keeps its line break and loses the spaces and tabs before it. Caxton's Text ▸ Whitespace menu has Trim Trailing Whitespace for the same job without a pattern.

Delete blank lines

sed -E '/^$/d' file.txt
grep -Ev '^$' file.txt

A find and replace cannot do this one in Caxton, because the match would have to include the line break and a regular expression stays within its line. Use Text ▸ Lines ▸ Remove Empty Lines, which deletes blank lines in one step and counts a line of spaces or tabs as blank, or Text ▸ Delete Lines Matching… with ^\s*$ and Regular expression on, which previews the count first.

Wrap every line in quotes

Find:     ^(.*)$
Replace:  "$1"

sed -E 's/^(.*)$/"\1"/' file.txt

Add a prefix or a suffix to every line

Find:     ^          Replace:  >
Find:     $          Replace:  ;

sed -E 's/^/> /' file.txt
sed -E 's/$/;/' file.txt

Both anchors are zero-width, so the replacement is inserted and nothing is removed. Caxton applies a $ replacement once per line, including the last line of a file that has no final line break.

Swap two comma-separated fields

Find:     ^([^,]*),([^,]*)$
Replace:  $2,$1

sed -E 's/^([^,]*),([^,]*)$/\2,\1/' file.txt

[^,]* means "anything but a comma," which is what keeps each group inside its own field. For a file with more columns, or with quoted fields that contain commas, open it as a table instead: Caxton's grid moves whole columns, and transforming a CSV column covers the rest.

Delete every line that contains a word

sed -E '/DEBUG/d' file.txt
grep -Ev 'DEBUG' file.txt

In Caxton, Text ▸ Delete Lines Matching… takes the pattern, shows a preview with the count and a few sample lines, and deletes them as one undo step. Deleting is Caxton Pro. To only look at the file without those lines, Filter Lines (⇧⌘L) hides them as a view and is free.

Keep only lines that match

grep -E 'ERROR' file.txt
sed -En '/ERROR/p' file.txt

Filter Lines is the free way to see only the matching lines in Caxton, with the match count in the status bar and the rest of the file one click away. Delete Lines Matching… with Keep only matching lines ticked makes it permanent, and Extract sends the matching lines to a new document; both change or create a file, so both are Caxton Pro.

When the file is large

None of this changes with size. Caxton counts every match in a 10 GB file exactly, highlights the first 2 million of them, and runs Replace All as one bulk edit with a single undo. A pattern that would run away stops after ten seconds per 100 MB scanned and says so in the bar instead of hanging. Find and replace in a huge file has the numbers, and find and replace across many files covers a folder at a time.

Paste a pattern into the find bar and watch every match highlight before you replace anything.

Download Caxton for Free

7-day free trial of Caxton Pro, every feature, no credit card required. After it, Caxton Free keeps opening, searching and filtering at any size.

Frequently asked questions

Why does my regex match too much?

Almost always because a quantifier is greedy: .* takes as much of the line as it can, so <.*> on a line with two tags matches from the first bracket to the last. Make it lazy with .*? in Caxton, or write a negated class such as <[^>]+> that cannot run past the closing bracket, which also works in grep and sed. A pattern with no anchor can match in the middle of a word too; add \b or ^ and $ to pin it down.

How do I match a newline in find and replace?

To insert one, put \n in the replacement; Caxton expands it in Regular expression and Extended modes, and sed needs a backslash followed by a real line break. To match one, turn regular expressions off and the \n toggle on, then search for the literal text with the break written as \n, such as first\nsecond. A regular expression in Caxton is evaluated one line at a time, so it never crosses a line break on its own.

What is the difference between ^ and \A?

In an engine that matches across a whole text, \A means the very start of the text while ^ can mean the start of any line when the multiline option is on. Caxton evaluates each line on its own, so both mean the start of the line. Apple's grep and sed also work line by line, and their -E syntax does not include \A at all, so use ^ there.

Can I use regular expressions across many files at once?

Yes. Edit ▸ Find ▸ Find in Files searches a folder without opening the files, with the same Regex option, and lists up to 10,000 matching lines per search. Searching is Caxton Free. Replace across those files, with a preview and a .bak beside every changed file, is Caxton Pro. The Terminal route is grep -rE for the search and sed -i '' -E on each file for the replace.

Sources