In this section · 04 Search itRegular expressions
04 · Search it · Find and query JSON
Find with regular expressions
Match email domains, ISO dates, id keys and empty strings with a pattern, and read the message an invalid one gives.
Input
{
"people": [
{ "name": "Ines", "email": "[email protected]" },
{ "name": "Marco", "email": "[email protected]" },
{ "name": "Yuki", "email": "[email protected]" }
]
}Do
- Press Find in the editor band, or
⌘F(Ctrl+Fon Windows and Linux). - Press Regular expression (
.*) on the bar. - Type
@example\.com$.
Result
1/2
/people/0/email
/people/2/emailA plain search looks for the letters you type. A regular expression looks for a shape: an address that ends in one domain, a string made only of digits, a key with a particular suffix. This page shows five such shapes, each on a document short enough to check by eye, and then the rules the Find bar follows when it tests one. It is part of the Find and query JSON guide.
What the example shows
Three people, two of them at example.com. The pattern ends in $, which pins it to the end of each value, and the dot is written as \. because a bare dot means any character at all. Without the dollar sign, an address such as [email protected] would match too. The counter shows two matches, and the two email values are marked. Marco’s address, at example.org, is left alone, and so are all three names.
Four more patterns
Dates written as year, month and day
Input
{ "created": "2026-09-22", "updated": "2026-09-22T10:15:00Z", "label": "2026 plan" }Do
- Press Regular expression (
.*) on the bar. - Type
^\d{4}-\d{2}-\d{2}$.
Result
1/1
/createdFour digits, a dash, two digits, a dash, two digits, and nothing else. The anchors at both ends are what reject the timestamp, which starts the same way but carries a time after it, and the label, which starts with a year and then goes on in words. Drop the final $ and the timestamp matches as well.
Keys that end in _id
Input
{ "user_id": 42, "order_id": "A-7", "paid": true, "idle": false }Do
- Press Regular expression (
.*) on the bar. - Open Search scope (
K·V) and pick Keys only. - Type
_id$.
Result
1/2
/user_id
/order_idWith the scope on keys, the pattern ignores every value and reads only the names. Both identifier fields match. paid ends in the letters id but not in an underscore followed by them, and idle only starts with them.
Empty strings
Input
{ "first": "Ines", "middle": "", "last": "Silva", "tags": [] }Do
- Press Regular expression (
.*) on the bar. - Type
^$.
Result
1/1
/middle^$ matches text with nothing between its start and its end, which is exactly an empty string. The empty array beside it is not a match: a list has no text of its own, so a text search never lands on one, whatever it holds.
Numbers, as written
Input
{ "zip": "01234", "count": 1234, "ratio": 0.5 }Do
- Press Regular expression (
.*) on the bar. - Type
^0\d.
Result
1/1
/zipA number is tested as the digits in the file, so a pattern can see a leading zero only where one can exist. JSON does not allow one on a number, which is why a postcode like 01234 has to be stored as a string, and the pattern finds that string and passes over the number 1234. The ratio is not a match either, since its zero is followed by a point rather than a digit.
What a pattern is tested against
The bar runs the pattern once for each key and once for each value, never for a whole line of the file and never for the quotes, commas and brackets around them. A string is tested as its content: the quotes are not part of it, and an escape such as \n has already become the character it stands for. A number is tested as it was typed, so 1.50 keeps its trailing zero. The words true, false and null are tested as those words. An object or an array is never a match on its own, although its key can be.
That per-value testing makes the anchors behave as you would want in a data file. ^ is the start of one value and $ is its end, so a pattern for a whole value is simply wrapped in the two. The scope menu applies as it does to plain text: keys, values, or both.
Flags
You type the pattern alone, without slashes or flags. Case is ignored unless Match case is on, which is the i flag being added or left out for you. The pattern is compiled in Unicode mode where it can be, so a class such as \p{L} matches a letter from any alphabet. A pattern that is only valid in the older, non-Unicode reading still works, rather than being refused. There is no global flag, because none is needed: the question asked of each value is only whether it matches.
When the pattern is invalid
Input
{ "grade": "a-" }Do
- Press Regular expression (
.*) on the bar. - Type
[a-.
Result
Invalid regular expression: /[a-/i: Unterminated character classA pattern that cannot be compiled replaces the counter with the reason, and the field is marked until the pattern is fixed. Here the bracket opens a character class that never closes. The wording is the browser’s own, so it can differ from one browser to the next: the message above is the one Chrome gives, and Firefox and Safari word theirs differently. Whatever was highlighted before the mistake stays highlighted while you type, so a pattern that is broken for a keystroke or two does not blank the screen.
A pattern inside a query
Input
{
"people": [
{ "name": "Ines", "email": "[email protected]" },
{ "name": "Marco", "email": "[email protected]" },
{ "name": "Yuki", "email": "[email protected]" }
]
}Do
- Press Query mode (
{ }) on the bar. - Type
@.email =~ /@example\.com$/.
Result
1/2
/people/0
/people/2Query mode has an operator for patterns, =~, which tests one field of each object rather than every value in the file. The match is now the person, not the email, which is what a filter or an extract usually wants. Here the pattern is written between slashes, and the flags come after the closing one: this form ignores Match case, so it is case-sensitive unless you add i. The JSONPath cheat sheet lists it with the other operators.
Open the editor to try a pattern on your own data, or read the next guide, Query JSON with JSONPath.