Regexp::Pattern(3pm)
๐ Regexp::Pattern ๐
okay so bestie, welcome to the manual page for Regexp::Pattern โ it's a User Contributed Perl Documentation situation, and it lives in section 3pm of the manual, iykyk ๐ซถ
โจ NAME โจ
Regexp::Pattern โ it's the convention/framework for modules that contain a collection of regexes ๐
Like, the whole vibe is: instead of every module out here inventing its own lil way of handing out regexes, this is the agreed-upon blueprint. A convention, a framework, a whole system, periodt.
๐ธ SPECIFICATION VERSION ๐ธ
0.2
That's the spec version, bestie. Write it down. ๐
๐ฆ VERSION ๐ฆ
This document describes version 0.2.14 of Regexp::Pattern (and it ships from the Perl distribution called Regexp-Pattern), released on 2020-04-01 โจ
๐ SYNOPSIS ๐
๐ Subroutine interface ๐
the classic, the icon, the moment:
use Regexp::Pattern; # exports re()
my $re = re('YouTube::video_id');
say "ID does not look like a YouTube video ID" unless $id =~ /\A$re\z/;
# a dynamic pattern (generated on-demand) with generator arguments
my $re2 = re('Example::re3', {variant=>"B"});
So use Regexp::Pattern; hands you the re() function (that's the export, no cap) ๐ซถ
Then you call re('YouTube::video_id') and boom, you've got yourself a regex. And if the ID doesn't match /\A$re\z/, you get that sad little message telling you it does not look like a YouTube video ID ๐ญ
And look at this โ re('Example::re3', {variant=>"B"}) gives you a dynamic pattern (generated on-demand) with generator arguments. You pass the args, it cooks the regex fresh for you ๐ฅ
๐ Hash interface ๐
okay this one is a la Regexp::Common but simpler, with a regular/non-magical hash that is only 1-level deep ๐
use Regexp::Pattern 'YouTube::video_id';
say "ID does not look like a YouTube video ID"
unless $id =~ /\A$RE{video_id}\z/;
# more complex example
use Regexp::Pattern (
're', # we still want the re() function
'Foo::bar' => (-as => 'qux'), # the pattern will be in your $RE{qux}
'YouTube::*', # wildcard import
'Example::re3' => (variant => 'B'), # supply generator arguments
'JSON::*' => (-prefix => 'json_'), # add prefix
'License::*' => (
# filtering options
-has_tag => 'family:cc', # only select patterns that have this tag
-lacks_tag => 'type:unversioned', # only select patterns that do not have this tag
-has_tag_matching => qr/^type:/, # only select patterns that have at least a tag matching this regex
-lacks_tag_matching => qr/^type:/, # only select patterns that do not have any tags matching this regex
# other options
-prefix => 'pat_', # add prefix
-suffix => '_license', # add suffix
),
);
Let me walk you through the group chat real quick ๐
use Regexp::Pattern 'YouTube::video_id';โ you import one pattern by name, and it lands in$RE{video_id}. Then/\A$RE{video_id}\z/does the matching ๐
Then the complex example, where every line is a whole mood:
're',โ we still want there()function, obviously, can't leave her behind ๐ซถ'Foo::bar' => (-as => 'qux'),โ the pattern will be in your$RE{qux}. Renaming! Cute!'YouTube::*',โ wildcard import, the asterisk ate ๐โจ'Example::re3' => (variant => 'B'),โ supply generator arguments, so it generates the variant you asked for'JSON::*' => (-prefix => 'json_'),โ add prefix, so all the JSON ones getjson_slapped on the front'License::*' => (...)โ and inside here we've got filtering options and other options:-has_tag => 'family:cc',โ only select patterns that have this tag-lacks_tag => 'type:unversioned',โ only select patterns that do not have this tag-has_tag_matching => qr/^type:/,โ only select patterns that have at least a tag matching this regex-lacks_tag_matching => qr/^type:/,โ only select patterns that do not have any tags matching this regex-prefix => 'pat_',โ add prefix-suffix => '_license',โ add suffix
like, filtering by tags AND decorating with prefix/suffix in one import? it's giving โจmain character energyโจ fr fr ๐ง
๐ DESCRIPTION ๐
okay so bestie, here's the whole vibe: Regexp::Pattern is a convention for organizing reusable regexp patterns in modules, and it's a framework that hands you convenience when you actually go to use those patterns in your program. two jobs, one icon. ๐
โจ Structure of an example Regexp::Pattern::* module โจ
lowkey the best way to get it is to just look at one, so here:
package Regexp::Pattern::Example;
our %RE = (
# the minimum spec
re1 => { pat => qr/\d{3}-\d{3}/ },
# more complete spec
re2 => {
summary => 'This is regexp for blah', # plaintext
description => <<'_',
A longer description in *Markdown* format.
_
pat => qr/\d{3}-\d{3}(?:-\d{5})?/,
tags => ['A','B'],
examples => [
# examples can be tested using 'test-regexp-pattern' script
# (distributed in Test-Regexp-Pattern distribution). examples can
# also be rendered in your POD using
# Pod::Weaver::Plugin::Regexp::Pattern.
{
str => '123-456',
matches => 1,
},
{
summary => 'Another example that matches',
str => '123-456-78901',
matches => 1,
},
{
summary => 'An example that does not match',
str => '123456',
matches => 0,
},
{
summary => 'An example that does not get tested',
str => '123456',
},
{
summary => 'Another example that does not get tested nor rendered to POD',
str => '234567',
matches => 0,
test => 0,
doc => 0,
},
],
},
# dynamic (regexp generator)
re3 => {
summary => 'This is a regexp for blah blah',
description => <<'_',
...
_
gen => sub {
my %args = @_;
my $variant = $args{variant} || 'A';
if ($variant eq 'A') {
return qr/\d{3}-\d{3}/;
} else { # B
return qr/\d{3}-\d{2}-\d{5}/;
}
},
gen_args => {
variant => {
summary => 'Choose variant',
schema => ['str*', in=>['A','B']],
default => 'A',
req => 1,
},
},
tags => ['B','C'],
examples => [
{
summary => 'An example that matches',
gen_args => {variant=>'A'},
str => '123-456',
matches => 1,
},
{
summary => "An example that doesn't match",
gen_args => {variant=>'B'},
str => '123-456',
matches => 0,
},
],
},
re4 => {
summary => 'This is a regexp that does capturing',
# it is recommended that your pattern does not capture, unless
# necessary. capturing pattern should tag with 'capturing' to let
# users/tools know.
tags => ['capturing'],
pat => qr/(\d{3})-(\d{3})/,
examples => [
{str=>'123-456', matches=>[123, 456]},
{str=>'foo-bar', matches=>[]},
],
},
re5 => {
summary => 'This is another regexp that is anchored and does (named) capturing',
# it is recommended that your pattern is not anchored for more
# reusability, unless necessary. anchored pattern should tag with
# 'anchored' to let users/tools know.
tags => ['capturing', 'anchored'],
pat => qr/^(?<cap1>\d{3})-(?<cap2>\d{3})/,
examples => [
{str=>'123-456', matches=>{cap1=>123, cap2=>456}},
{str=>'something 123-456', matches=>{}},
],
},
);
so yeah โ a Regexp::Pattern::* module must declare a package global hash variable named %RE. the hash keys are pattern names, and the hash values are pattern definitions shaped like defhashes (go peek at DefHash for that whole situation).
a pattern name should be a simple identifier matching this regexp, no cap:
/\A[A-Za-z_][A-Za-z_0-9]*\z/
and then the definition for the qualified pattern name Foo::Bar::baz lives in %Regexp::Pattern::Foo::Bar::RE under the hash key baz. yes, that's the whole address. ๐
at bare minimum, a pattern definition hash has to be this and nothing more:
{ pat => qr/.../ }
but you can absolutely stack more stuff from the defhash specification on top โ summary, description, tags, and so on. for example (this one's straight outta Regexp::Pattern::CPAN):
{
summary => 'PAUSE author ID, or PAUSE ID for short',
pat => qr/[A-Z][A-Z0-9]{1,8}/,
description => <<~HERE,
I'm not sure whether PAUSE allows digit for the first letter. For safety
I'm assuming no.
HERE
examples => [
{str=>'PERLANCAR', matches=>1},
{str=>'BAD ID', anchor=>1, matches=>0},
],
}
Examples. your regexp specification can include an examples property (there's one up above if you wanna peek). the value of examples is an array, and each element should be a defhash. for every example, the minimum you should specify is str (the string that gets matched against the regexp), gen_args (a hash of arguments to use when generating a dynamic regexp pattern), and matches (a boolean saying whether the regexp should match the string or not โ or an array/hash that specifies the captures). and ofc you can throw in other defhash properties too, like summary, description, etc. other example properties might show up in the future, so stay tuned. ๐
if you build your distribution with Dist::Zilla, you can use the plugin [Regexp::Pattern] to test the examples while building, and the Pod::Weaver plugin [-Regexp::Pattern] to render those examples right into your POD. slay.
๐ธ Using a Regexp::Pattern::* module ๐ธ
Standalone
a Regexp::Pattern::* module works perfectly fine standalone โ like, you don't need the Regexp::Pattern framework at all, because it's literally just data you can grab with normal means:
use Regexp::Pattern::Example;
say "Input does not match blah"
unless $input =~ /\A$Regexp::Pattern::Example::RE{re1}{pat}\z/;
Via Regexp::Pattern, sub interface
Regexp::Pattern (this very module, hi) also gives you the re() function to help retrieve a regexp pattern. head down to "re" for the full tea.
Via Regexp::Pattern, hash interface
and additionally, Regexp::Pattern (since v0.2.0) lets you import regexp patterns straight into your %RE package hash variable โ a la Regexp::Common, except simpler, because the hash is just a regular hash: only 1-level deep, not magical, no tricks. ๐ช
to import, you pass qualified pattern names as the import arguments:
use Regexp::Pattern 'Q::pat1', 'Q::pat2', ...;
each qualified pattern name can optionally be followed by a list of name-value pairs. a pair name can be an option name (which is a dash followed by a word, e.g. -as, -prefix) or a generator argument name for a dynamic pattern.
Wildcard import. instead of a qualified pattern name, you can use the 'Module::SubModule::*' wildcard syntax to import every pattern from a pattern module.
Importing into a different name. you can add the import option -as to import under a different name, like:
use Regexp::Pattern 'YouTube::video_id' => (-as => 'yt_id');
Prefix and suffix. you can also slap a prefix and/or suffix onto the imported name:
use Regexp::Pattern 'Example::*' => (-prefix => 'example_');
use Regexp::Pattern 'Example::*' => (-suffix => '_sample');
Filtering. when you're wildcard-importing, you can pick exactly which patterns you want using a combo of these options:
-has_tagโ only select patterns that have a specified tag-lacks_tagโ only select patterns that do not have a specified tag-has_tag_matchingโ only select patterns that have at least one tag matching the specified regex pattern-lacks_tag_matchingโ only select patterns that do not have any tags matching the specified regex pattern
๐ Recommendations for writing the regex patterns ๐
- Regexp pattern should in general be written as a
qr//literal instead of string.
that is:
pat => qr/foo[abc]+/,
is preferred over:
pat => 'foo[abc]+',
using a string literal is less desirable because of the lack of compile-time checking. ๐ซ the one exception to this rule is when you want to delay regex compilation for some reason โ e.g. you want your user to compile the patterns themselves using a different regex engine (see the re::engine::* modules on CPAN).
- Regexp pattern should not be anchored (unless really necessary).
that is:
pat => qr/foo/,
is preferred over:
pat => qr/^foo/, # or qr/foo$/, or qr/\Afoo\z/
adding anchors limits how reusable the pattern is. when composing a pattern, the user can add anchors herself if she needs them. ๐โโ๏ธ
when you do define an anchored pattern, adding the tag anchored is recommended:
tags => ['anchored'],
- Regexp pattern should not contain capture groups (unless really necessary).
adding capture groups limits reusability too, because it can mess with the groups of the composed pattern. when composing a pattern, the user can add captures herself if she needs them.
when you define a capturing pattern, adding the tag capturing is recommended:
tags => ['capturing'],
โจ FUNCTIONS โจ
re
Exported by default. gets you a regexp pattern by name from a Regexp::Pattern::* module.
Usage:
re($name[, \%args ]) => $re
$name is MODULE_NAME::PATTERN_NAME, where MODULE_NAME is the name of a Regexp::Pattern::* module without the Regexp::Pattern:: prefix, and PATTERN_NAME is a key into the %RE package global hash inside that module. a dynamic pattern can accept arguments for its generator, and you pass those along as a hashref in the second argument of re().
Anchoring. you can also drop -anchor => 1 into %args. that conveniently wraps the regex inside qr/\A(?:...)\z/. to add only left anchoring, specify -anchor => 'left' (that gives you qr/\A(?:...)/). to add only right anchoring, specify -anchor => 'right' (that gives you qr/(?:...)\z/).
heads up bestie: it dies when the pattern by the name $name can't be found โ either because the module can't be loaded, or because the pattern with that name isn't found in the module. ๐ญ so maybe wrap it if you're feeling fragile.
๐ฌ FAQ ๐ฌ
๐ฅบ My pattern is not anchored, but what if I want to test the anchored version?
Bestie, it's so easy. You can add anchor=>1 or gen_args=>{-anchor=>1} in the example, for example:
{
summary => 'PAUSE author ID, or PAUSE ID for short',
pat => qr/[A-Z][A-Z0-9]{1,8}/,
description => <<~HERE,
I'm not sure whether PAUSE allows digit for the first letter. For safety
I'm assuming no.
HERE
examples => [
{str=>'PERLANCAR', matches=>1},
{str=>'BAD ID', anchor=>1, matches=>0, summary=>"Contains whitespace"},
{str=>'NAMETOOLONG', gen_args=>{-anchor=>1}, matches=>0, summary=>"Too long"},
],
}
๐ HOMEPAGE ๐
Please visit the project's homepage at <https://metacpan.org/release/Regexp-Pattern>. โจ
๐ฆ SOURCE ๐ฆ
Source repository is at <https://github.com/perlancar/perl-Regexp-Pattern>. ๐ฆ
๐ BUGS ๐
Please report any bugs or feature requests on the bugtracker website <https://rt.cpan.org/Public/Dist/Display.html?Name=Regexp-Pattern>
When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. ๐
like fr fr, a failing test is the love language of maintainers ๐
๐ SEE ALSO ๐
Regexp::Common.Regexp::Patternis an alternative toRegexp::Common.Regexp::Patternoffers simplicity and lower startup overhead. Instead of a magic hash, you retrieve available regexes from normal data structure or via the providedre()function.Regexp::Patternalso provides a hash interface, albeit the hash is not magic. ๐ชRegexp::Common::RegexpPattern, a bridge module to use patterns inRegexp::Pattern::*modules viaRegexp::Common. ๐Regexp::Pattern::RegexpCommon, a bridge module to use patterns inRegexp::Common::*modules viaRegexp::Pattern. ๐App::RegexpPatternUtils๐- If you use Dist::Zilla:
Dist::Zilla::Plugin::Regexp::Pattern,Pod::Weaver::Plugin::Regexp::Pattern,Dist::Zilla::Plugin::AddModule::RegexpCommon::FromRegexpPattern,Dist::Zilla::Plugin::AddModule::RegexpPattern::FromRegexpCommon. ๐ฎโ๐จ Test::Regexp::Patternandtest-regexp-pattern. ๐งช
๐ AUTHOR ๐
perlancar <perlancar@cpan.org> ๐
๐ COPYRIGHT AND LICENSE ๐
This software is copyright (c) 2020, 2019, 2018, 2016 by perlancar@cpan.org.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. ๐
okay that's the whole page bestie, go forth and pattern-match responsibly ๐
this was perl v5.36.0, generated 2022-11-29, for Regexp::Pattern(3pm) โ mwah, stan, bye ๐ซถโจ๐ธ
๐ฆ where this page comes from
- debian bookworm: libregexp-pattern-perl 0.2.14-2 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libregexp-pattern-perl 0.2.14-2 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libregexp-pattern-perl 0.2.14-2 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu questing: libregexp-pattern-perl 0.2.14-2
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms