Test regex against samples and inspect captured groups
Run one regular expression over a list of sample lines and see which match and what each group captured: of three samples, two match, and Gadget: 7 yields Gadget and 7. Every line is tested on its own, so one result never skews the next. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Pattern
- ^(?<name>[A-Za-z]+):\s*(\d+)$
- Flags
- i
- Samples
- Widget: 42, not a record, Gadget: 7
- Sample count
- 3
- Matched count
- 2
Testing a regular expression against one carefully chosen string rarely tells the whole story. Real inputs include valid records, near misses, unexpected capitalization, optional fields, and repeated values. This tool applies one ECMAScript regex pattern and its flags independently to a list of sample strings. It reports which samples matched, every match found when global matching is enabled, and the numbered and named groups that actually participated. An invalid pattern or unsupported flag produces a clear input error before any sample results are returned.
Build a sample set that challenges the pattern
Start with the regular expression body exactly as JavaScript would receive it, without wrapping slash characters. Add flags separately so there is no ambiguity between a literal slash and a delimiter. Then provide several samples that represent both expected matches and deliberate failures.
A useful set includes an ordinary valid value, a boundary case, different capitalization when the case-insensitive flag matters, an empty or incomplete value, and a string containing similar text that should not qualify. Anchors such as caret and dollar sign are especially important when you mean to validate the whole sample rather than merely find a substring. Each sample is evaluated independently with a fresh regular expression, so state from a global or sticky search in one string cannot leak into the next.
Read matches and captured groups accurately
For every successful sample, the matches array contains the exact matched text and its zero-based UTF-16 index, which follows JavaScript string indexing. Numbered capture groups appear in opening-parenthesis order as objects with a number and value. Optional groups that did not participate are omitted, avoiding ambiguous null fields while preserving the group number for every value that did participate.
Without the global flag, ECMAScript returns the first match in a sample. With the global flag, the tool continues through non-overlapping matches and reports each one. Zero-length matches receive special handling so a pattern that can match an empty string advances safely instead of looping forever.
Sticky matching keeps native JavaScript behavior: the search must succeed exactly at the current position. These details matter when a pattern extracts records rather than merely validates them. Inspect both the matched text and captures, since a true matched value can still hide a capture boundary that is too broad, too narrow, or attached to the wrong alternative.
Use errors and limits in automated checks
The pattern and flags are compiled before sample evaluation begins. Flags must be supported ECMAScript flags and may not be duplicated. This fail-fast contract means a malformed expression never produces a misleading list of non-matches.
The capability is deterministic and performs no network calls, model inference, random selection, or clock-based work, so identical inputs produce identical structured outputs. Practical limits cap pattern length, sample count, individual sample length, and matches per sample to prevent accidental runaway workloads. When the pattern changes, reviewers can see whether the intended examples still pass and whether rejected examples remain rejected.
What you can do with it
Validate extraction patterns
Check log, filename, identifier, or record patterns against realistic examples and inspect each extracted field.
Protect a regex refactor
Keep positive and negative samples in a regression suite so changing a pattern does not silently broaden or narrow it.
Debug capture groups
Compare numbered and named capture values across several input shapes before integrating the expression into application code.
FAQ
Should the pattern include slash delimiters?
No. Send only the regular expression body, and put flags such as g, i, or m in the flags field.
Why does a sample have only one match?
Without the global flag, ECMAScript returns only the first match. Add g when you want all non-overlapping matches.
Which samples should I include in a test?
Include an ordinary valid value, a boundary case, a different capitalization if case matters, an empty or incomplete value, and similar text that should not match. That way you see both what the expression accepts and what it rejects.
Why do I need the caret and the dollar sign to validate a whole value?
They force the match to start at the beginning of the sample and end at its very end. Without them, a line passes just because it contains the searched text somewhere, even when the rest of it is wrong.
What happens if my regular expression has an error?
The expression and its options are checked before any sample is tested, and a mistake is reported clearly. You never get a misleading list of failed samples caused by a broken expression.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/web/regex-test \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"pattern":"^(?<name>[A-Za-z]+):\\s*(\\d+)$","samples":["Widget: 42","not a record","Gadget: 7"]}'const res = await fetch("https://api.kit.forhosting.com/web/regex-test", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"pattern": "^(?<name>[A-Za-z]+):\\s*(\\d+)$",
"samples": [
"Widget: 42",
"not a record",
"Gadget: 7"
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/web/regex-test",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"pattern": "^(?<name>[A-Za-z]+):\\s*(\\d+)$",
"samples": [
"Widget: 42",
"not a record",
"Gadget: 7"
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/web/regex-test", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"pattern":"^(?<name>[A-Za-z]+):\\\\s*(\\\\d+)$","samples":["Widget: 42","not a record","Gadget: 7"]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"pattern":"^(?<name>[A-Za-z]+):\\s*(\\d+)$","samples":["Widget: 42","not a record","Gadget: 7"]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/web/regex-test", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"pattern": "^(?<name>[A-Za-z]+):\\s*(\\d+)$",
"samples": [
"Widget: 42",
"not a record",
"Gadget: 7"
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "web.regex_test",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_pattern_chars | 2000 |
max_samples | 500 |
max_sample_chars | 100000 |
max_matches_per_sample | 10000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Build a sample set that challenges the pattern
The result preserves the original sample and gives it a matched boolean, making the response straightforward to scan manually or assert in an automated test. This structure helps turn vague confidence in a pattern into a repeatable set of examples that documents its intended boundary.
Read matches and captured groups accurately
Named captures also appear in named_groups when they participated.
Use errors and limits in automated checks
If ECMAScript rejects the pattern, the request fails with an invalid_input error whose message identifies it as an invalid regex pattern and includes the engine's useful compilation detail. In a continuous-integration job, store representative samples beside the code that consumes the pattern, call this capability, and assert matched_count plus the capture values that matter.
Technical questions
What happens when the regex pattern is invalid?
The request fails with an invalid_input error before any samples are evaluated.
Are named capture groups included?
Yes. Participating named captures appear in named_groups, while numbered captures are listed with their group numbers.
What does it cost?
The API price is $0.002 per request. The on-page browser runner is free.