PHPackages                             liquidrazor/liquid-regex - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. liquidrazor/liquid-regex

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

liquidrazor/liquid-regex
========================

An intuitive, simple and powerful Regex library for PHP.

v0.1.0(9mo ago)02.7kMITPHPPHP &gt;=8.3

Since Sep 25Pushed 8mo agoCompare

[ Source](https://github.com/LiquidRazor/LiquidRegex)[ Packagist](https://packagist.org/packages/liquidrazor/liquid-regex)[ RSS](/packages/liquidrazor-liquid-regex/feed)WikiDiscussions main Synced today

READMEChangelogDependenciesVersions (3)Used By (0)

LiquidRazor Regex
=================

[](#liquidrazor-regex)

An intuitive, small, and fast **regular expression helper for PHP 8.3+** with clean result objects and a few ergonomic utilities around PCRE.

> Package: `liquidrazor/liquid-regex` • License: MIT

---

✨ Features
----------

[](#-features)

- **Fluent, tiny API** for matching and replacing.
- **Lazy, rewindable match results** with `Iterator`, `ArrayAccess`, `Countable`, and `JsonSerializable` support.
- **Deterministic result shapes** via `ResultTypes` (numeric, associative, or both) and a `STRICT` filter.
- **PCRE helpers** to check version/JIT support and validate pattern syntax.
- **Exceptions you can catch** with informative messages bubbled from PCRE.

---

🚧 Requirements
--------------

[](#-requirements)

- PHP **8.3** or newer
- PCRE (bundled with PHP)

---

📦 Installation
--------------

[](#-installation)

```
composer require liquidrazor/regex
```

The library is namespaced under `LiquidRazor\Regex` and PSR‑4 autoloaded per `composer.json`.

---

🧠 Concepts at a Glance
----------------------

[](#-concepts-at-a-glance)

### `Regex` — main entry point

[](#regex--main-entry-point)

The `Regex` class is the main façade. It also memoizes compiled instances by pattern:

```
use LiquidRazor\Regex\Regex;

$re = Regex::compiled('/(?P[a-z]+)/i');
```

From there you can **match** or **replace** (see examples below).

### `ResultTypes` — control your result shape

[](#resulttypes--control-your-result-shape)

Choose how match arrays are exposed:

```
use LiquidRazor\Regex\Result\ResultTypes;

// Types
ResultTypes::INDEXED;      // numeric keys only (0, 1, 2, ...)
ResultTypes::ASSOCIATIVE;  // named keys only ('foo', 'bar', ...)
ResultTypes::BOTH;         // default: include both kinds

// Modifier
ResultTypes::STRICT;       // when used, filters to "pure" keys only:
//   - with INDEXED: keeps only truly integer keys (0,1,2...)
//   - with ASSOCIATIVE: keeps only truly string, non-numeric keys
```

This lets you request exactly the view you need (e.g., only named groups). You can bit‑OR flags:

```
$flags = ResultTypes::ASSOCIATIVE | ResultTypes::STRICT;
```

### `Flags` (PCRE capture flags)

[](#flags-pcre-capture-flags)

Extra capture behavior forwarded to PCRE:

```
use LiquidRazor\Regex\Lib\Flags;

Flags::OffsetCapture;   // include offsets for each capture
Flags::UnmatchedAsNull; // unmatched subpatterns become null
```

---

🚀 Quick start
-------------

[](#-quick-start)

### 1) Find the first match

[](#1-find-the-first-match)

```
use LiquidRazor\Regex\Regex;
use LiquidRazor\Regex\Result\ResultTypes;

$re = Regex::compiled('/(?P[a-z]+)/i');

$result = $re->match(
    haystack: "Hello, World!",
    resultType: ResultTypes::ASSOCIATIVE | ResultTypes::STRICT // named keys only
);

if ($result->didMatch) {
    // ArrayAccess
    $first = $result[0]; // or $result['word'] in ASSOCIATIVE mode

    // Countable
    $count = count($result);

    // Iteration (rewindable)
    foreach ($result as $k => $v) {
        // ...
    }

    // JSON
    $json = json_encode($result, JSON_PRETTY_PRINT);
}
```

### 3) Replace

[](#3-replace)

```
use LiquidRazor\Regex\Regex;
use LiquidRazor\Regex\Result\Replace\Result;

$re = Regex::compiled('/(\d+)/');
$replace = $re->replace('abc 123 xyz 45', '#');

$replace->pattern;   // the pattern used
$replace->count;     // number of replacements performed
(string)$replace;    // casts to the replaced string (or JSON if array)
```

`LiquidRazor\Regex\Result\Replace\Result` implements `Stringable`. If the replacement result is an array (e.g., when replacing in arrays), `__toString()` returns JSON.

---

🎛️ Controlling result shapes
----------------------------

[](#️-controlling-result-shapes)

The `LiquidRazor\Regex\Result\Matches\Result` object exposes a lazy, memoized sequence of match entries. You decide which keys appear using `ResultTypes`:

- `INDEXED`: keeps only integer keys (0,1,2…). With `STRICT`, **filters out** any non-integer keys.
- `ASSOCIATIVE`: keeps only named group keys. With `STRICT`, **filters out** numeric-looking strings.
- `BOTH`: includes both numeric and associative keys (default). Combine with `STRICT` to prune mixed keys.

The object supports:

- `Iterator` (rewindable)
- `ArrayAccess` (read-only; attempting to mutate throws `ImmutableException`)
- `Countable`
- `JsonSerializable`

```
// Read-only access (mutations throw)
$value = $result['name'] ?? $result[0];
```

If there was **no match**, the `Result` is empty with `didMatch === false` (safe to iterate/count/JSON-encode).

---

🧩 PCRE helpers
--------------

[](#-pcre-helpers)

Use the `Pcre` static utility for environment checks:

```
use LiquidRazor\Regex\Pcre;

Pcre::versionString();   // "PCRE x.y (major.minor)"
Pcre::isJitSupported();  // bool
Pcre::isValid('/^[a-z]+$/i'); // quick sanity check for "/.../flags"-style patterns
```

> Note: `isValid()` only checks a basic `/.../flags` shape, also does compile the pattern and checks the result. If compilation fails, it returns false.

---

⚠️ Exceptions
-------------

[](#️-exceptions)

The library centralizes PCRE errors through `LiquidRazor\Regex\Exception` classes:

- `PcreException` – wraps `preg_last_error()` &amp; message
- `Exception` – currently extends `PcreException` for convenience
- `ImmutableException` – thrown on attempts to mutate read-only results

In practice, most API calls either return a `Result` object or throw on **internal** PCRE errors (e.g., bad backtrack limit).

```
use LiquidRazor\Regex\Exception\PcreException;

try {
    $re = Regex::compiled('/(?P[a-z]+)/i');
    $res = $re->match('...');
} catch (PcreException $e) {
    // inspect $e->getMessage(), $e->getCode()
}
```

---

📚 API sketch
------------

[](#-api-sketch)

> The following reflects the current source structure at a high level. Some signatures may evolve.

- `Regex::compiled(string $pattern): Regex`
- `Regex->match(string $haystack, int $resultType = ResultTypes::BOTH, Flags ...$captureFlags): LiquidRazor\Regex\Result\Matches\Result`
- `Regex->replace(string|array $subject, string|callable $replacement, int $limit = -1): LiquidRazor\Regex\Result\Replace\Result`

Result types:

- `LiquidRazor\Regex\Result\Matches\Result`
    - Properties: `pattern`, `haystack`, `didMatch`
    - Interfaces: `Iterator`, `ArrayAccess` (read-only), `Countable`, `JsonSerializable`
- `LiquidRazor\Regex\Result\Replace\Result implements Stringable`
    - Properties: `pattern`, `count`, `replaced`
    - Casting: `(string)$result` yields the final string (or JSON if array)

Helpers:

- `LiquidRazor\Regex\Pcre`
    - `versionString(): string`
    - `isJitSupported(): bool`
    - `isValid(?string $pattern): bool`

Enums / constants:

- `LiquidRazor\Regex\Lib\Flags` — `Default`, `OffsetCapture`, `UnmatchedAsNull`
- `LiquidRazor\Regex\Result\ResultTypes` — `INDEXED`, `ASSOCIATIVE`, `BOTH`, `STRICT`

---

✅ Examples
----------

[](#-examples)

### Only named groups, strictly

[](#only-named-groups-strictly)

```
use LiquidRazor\Regex\Regex;
use LiquidRazor\Regex\Result\ResultTypes;

$re = Regex::compiled('/(?P\d+)-(?P[a-z]+)/i');
$res = $re->match('42-Answer', ResultTypes::ASSOCIATIVE | ResultTypes::STRICT);

echo json_encode($res, JSON_PRETTY_PRINT);
/*
{
  "num": "42",
  "word": "Answer"
}
*/
```

### With offsets and nulls for unmatched

[](#with-offsets-and-nulls-for-unmatched)

```
use LiquidRazor\Regex\Regex;
use LiquidRazor\Regex\Lib\Flags;

$re = Regex::compiled('/(a)?(b)/');
$res = $re->match('xb', Flags::OffsetCapture, Flags::UnmatchedAsNull);

// Offsets included; the first group is null because it didn't match.
```

---

🧪 Testing
---------

[](#-testing)

You can plug this library into any test runner. The result objects are easy to snapshot by JSON encoding.

```
$this->assertJsonStringEqualsJsonString(
    '{"word":"Hello"}',
    json_encode($result, JSON_THROW_ON_ERROR)
);
```

---

🤝 Contributing
--------------

[](#-contributing)

- Open an issue for design/API discussions.
- Keep the API minimal and predictable.
- PRs welcome with tests and docs for new behavior.

---

📄 License
---------

[](#-license)

[MIT](./LICENSE) © LiquidRazor

###  Health Score

35

—

LowBetter than 77% of packages

Maintenance59

Moderate activity, may be stable

Popularity23

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 50% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

282d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4306922?v=4)[Noramarth](/maintainers/Noramarth)[@Noramarth](https://github.com/Noramarth)

---

Top Contributors

[![hktr92](https://avatars.githubusercontent.com/u/7689151?v=4)](https://github.com/hktr92 "hktr92 (6 commits)")[![Noramarth](https://avatars.githubusercontent.com/u/4306922?v=4)](https://github.com/Noramarth "Noramarth (6 commits)")

### Embed Badge

![Health badge](/badges/liquidrazor-liquid-regex/health.svg)

```
[![Health](https://phpackages.com/badges/liquidrazor-liquid-regex/health.svg)](https://phpackages.com/packages/liquidrazor-liquid-regex)
```

###  Alternatives

[kartik-v/yii2-grid

Yii 2 GridView on steroids. Various enhancements and utilities for the Yii 2.0 GridView widget.

5546.9M182](/packages/kartik-v-yii2-grid)[lochmueller/calendarize

Create a structure for timely controlled tables (e.g. events) and one plugin for the different output of calendar views (list, detail, month, year, day, week...). The extension is shipped with one default event table, but you can also 'calendarize' your own table/model. It is completely independent and configurable! Use your own models as event items in this calender. Development on https://github.com/lochmueller/calendarize

76166.2k14](/packages/lochmueller-calendarize)[jaybizzle/safeurl

A Laravel package to create safe, SEO friendly urls

1789.6k1](/packages/jaybizzle-safeurl)[clausnz/php-helpers

A Collection of useful php helper functions.

3810.4k](/packages/clausnz-php-helpers)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
