From a118b7c40742c90d488def38b22ab79d28d36cba Mon Sep 17 00:00:00 2001 From: rudashi Date: Thu, 6 Jun 2024 07:56:55 +0200 Subject: [PATCH] Added IPv6 Pattern --- docs/usage.md | 2 +- docs/usage/patterns.md | 15 ++++ src/Patterns/IPv6AddressPattern.php | 15 ++++ tests/Feature/IPv6AddressTest.php | 102 ++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/Patterns/IPv6AddressPattern.php create mode 100644 tests/Feature/IPv6AddressTest.php diff --git a/docs/usage.md b/docs/usage.md index be064a9..8815b6c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -67,7 +67,7 @@ You can start creating your regex by using `Regex::build()`. The `build()` metho - [`date`](usage/patterns#date) - time - [`IPv4 address`](usage/patterns#ipv4-address) -- IPv6 address +- [`IPv6 address`](usage/patterns#ipv6-address) - [`mac address`](usage/patterns#mac-address) - [`email`](usage/patterns#email) - [`url`](usage/patterns#url) diff --git a/docs/usage/patterns.md b/docs/usage/patterns.md index 807ac72..93c789b 100644 --- a/docs/usage/patterns.md +++ b/docs/usage/patterns.md @@ -64,6 +64,21 @@ $pattern = Regex::build([\Rudashi\Patterns\IPAddressPattern::class]) // /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/ ``` +### `IPv6 address` + +You can use the predefined `IPv6AddressPattern` pattern to find whether a given text contains IP addresses. This pattern can only find addresses that match **IPv6**. + +```php +use Rudashi\Regex; + +$pattern = Regex::build([Rudashi\Patterns\IPv6AddressPattern::class]) + ->start() + ->ipv6() + ->end(); + +// /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|...|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/ +``` + ### `MAC address` To find whether a given text contains MAC addresses, you can use the predefined `MACAddressPattern` pattern. diff --git a/src/Patterns/IPv6AddressPattern.php b/src/Patterns/IPv6AddressPattern.php new file mode 100644 index 0000000..97f17c1 --- /dev/null +++ b/src/Patterns/IPv6AddressPattern.php @@ -0,0 +1,15 @@ + $fluent->number()->letter(last: 'f'); + $group = fn (FluentBuilder $fluent) => $fluent->anyOf($anyOf)->between(1, 4)->character(':'); + $subGroup = fn (FluentBuilder $fluent) => $fluent->character(':')->anyOf($anyOf)->between(1, 4); + + $regex = Regex::for($context) + ->start() + ->group(fn (FluentBuilder $fluent) => $fluent + ->group($group)->between(7, 7)->anyOf($anyOf)->between(1, 4) + ->or + ->group($group)->between(1, 7)->character(':') + ->or + ->group($group)->between(1, 6)->character(':')->anyOf($anyOf)->between(1, 4) + ->or + ->group($group)->between(1, 5)->group($subGroup)->between(1, 2) + ->or + ->group($group)->between(1, 4)->group($subGroup)->between(1, 3) + ->or + ->group($group)->between(1, 3)->group($subGroup)->between(1, 4) + ->or + ->group($group)->between(1, 2)->group($subGroup)->between(1, 5) + ->or + ->anyOf($anyOf)->between(1, 4)->character(':') + ->group(fn (FluentBuilder $fluent) => $fluent->group($subGroup)->between(1, 6)) + ->or + ->character(':') + ->group(fn (FluentBuilder $fluent) => $fluent->group($subGroup)->between(1, 7)->or->character(':')) + ) + ->end(); + + expect($regex) + ->toBeInstanceOf(FluentBuilder::class) + ->get()->toBe('/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/') + ->check()->toBe($expectation); +})->with('ips v6'); + +describe('predefined IP ADDRESS pattern', function () { + beforeEach(function () { + $this->builder = new FluentBuilder(patterns: [IPv6AddressPattern::class]); + }); + + it('validates', function (string $context, bool $expectation) { + $regex = $this->builder->setContext($context)->start()->ipv6()->end(); + + expect($regex->check()) + ->toBe($expectation); + })->with('ips v6'); + + it('finds an ipv6 address s in text', function () { + $context = "I visited a website with the IPv6 address: 2001:0db8:85a3:0000:8a2e:0370:7334, which \n + contained many interesting articles. Another site with the address 2001:0db8:0000:0042:0000:8a2e:0370:7334 \n + I found while browsing tech news. My friend uses a server with the address fe80:0000:0000:0000:1ff:fe23:4567:890a in \n + his home network. On my laptop, I configured the IPv6 address: 2001:0db8:1234:0000:0000:0000:0000:0001."; + + $regex = $this->builder->setContext($context)->ipv6(); + + expect($regex->match()) + ->toHaveCount(3) + ->toMatchArray([ + '2001:0db8:0000:0042:0000:8a2e:0370:7334', + 'fe80:0000:0000:0000:1ff:fe23:4567:890a', + '2001:0db8:1234:0000:0000:0000:0000:0001', + ]); + }); +}); + +it('check IPv6AddressPattern', function () { + $pattern = new IPv6AddressPattern(); + + expect($pattern) + ->toBeInstanceOf(IPv6AddressPattern::class) + ->getName()->toBe('ipv6') + ->getPattern()->toBe('(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))'); +});