Simple library for regular expressions in PHP.
😎 T-Regx The Dinosaur is really proud to announce its fifth beta version! Despite the beta suffix, it's 100% suitable for production use. This time, we added some security fixed and performed some throughout internal changes to prepare ourselves for the big changes, later down the track.
The detailed list of changes is in ChangeLog.md.
x
- extended flag in prepared patterns
preg_quote()
incorrectly (passing more than one character to it), so now preg::quote()
throws \InvalidArgumentException
for more than one character passed to preg::quote()
.pattern()->delimiter()
to pattern()->delimited()
MatchGroup.equals()
, that allows to compare a potentially unmatched group with a string.pattern()->match()->group()->filter()
method. #22pattern()->replace()->by()->mapAndCallback()
, which first translates a match by a dictionary (like map()
), and then passes it through callback, before replacing (like callback()
).TypeError
,
instead of MalformedPatternException
.The detailed list of changes is also in ChangeLog.md.
See ya later, aligator!
😢 T-Regx The Dinosaur is sad to announce that we've introduced a bug in 0.9.11 version (TypeError
when no argument was passed to group()->orThrow()
).
It's not a big deal, but it's something we should've caught before the release. Our bad!
TypeError
(Bug introduced in 0.9.11, fixed in 0.9.12)This version of course is listed as a change in ChangeLog.md.
See ya later, aligator!
😎 T-Regx The Dinosaur is really proud to announce its sixth beta version! Despite the beta suffix, it's 100% suitable for production use. This time, we added another higher-level API in replacing; proper handling of duplicate named groups (with /J
modifier), more methods to T-Regx-specific exceptions, PHP gotchas handling and preparation for PHP 8.
The detailed list of changes is in ChangeLog.md.
Breaking changes
Deprecation
Features
Add pattern()->replace()->focus(group)
#82
Allows you to "focus" on a certain group while replacing, so only that one particular group will be replaced. In the future, there are plans for "focus" method that can replace an arbitrary list of groups.
Added proper handling of /J
flag #84
The detailed list of changes is also in ChangeLog.md.
Other
#2
,
and named groups as 'group'
.SafeRegex
After calling preg_match()
with overflowing offset, preg_last_error()
would return
PREG_INTERNAL_ERROR
, which T-Regx would handle, throwing RuntimePregException
with proper message.
Negative offsets would be ignored.
Since now, T-Regx throws \InvalidArgumentException
in both cases.
See ya later, aligator!
😎 T-Regx The Dinosaur is really proud to announce its seventh beta version! Despite the beta suffix, it's 100% suitable for production use. This time, we bring replacements excpectations, which allow you to declare the wanted replacements performed and formats, which lets you simplify patterns for your users to create psueudo-patterns or meta-patterns if you will.
The formats are a way of building patterns, so that you can assign tokens to regular expressions; and allow an arbitrary string (say, user input) to be used to build the final pattern, using the regular expressions.
Dear user. Type a mask, where
%d
is a digit, and%w
is letter,%ws
to include whitespace,%%
to include%
sign.
['mask' => '(search:%w,age:%d)']
$mask = $_GET['mask'];
Pattern::of()
and Pattern::inject()
)
Pattern::format($mask, [
'%d' => '\d+',
'%w' => '[a-z]+',
'%ws' => '\s+',
'%%' => '%'
]);
That would be the equivalent of Pattern::of('\\(search:[a-z]+,age:\d+\\)')
. Characters in $mask
are treated utterly as text (totally quoted), and only the patterns on the right-hand side of the tokens are treated as regular expressions.
The detailed list of changes is in ChangeLog.md, and here's a summary:
Breaking changes
DetailGroup.replace()
to DetailGroup.substitute()
match().groupBy().texts()
to match().groupBy().all()
Utf8OffsetPregException
to UnicodeOffsetException
SubjectEncodingPregException
to SubjectEncodingException
CatastrophicBacktrackingPregException
to CatastrophicBacktrackingException
RecursionLimitPregException
to RecursionException
JitStackLimitPregException
to JitStackLimitException
Bug fixes
"(hello)\\"
) would throw
MalformedPatternException
with a really weird message, exposing the implementation details. Now the message
is Pattern may not end with a trailing backslash
.match()->offsets()->fluent()
ReplaceDetail
would return malformed modifiedSubject()
for utf-8 replacementsFeatures
match()->flatMapAssoc()
#88replace()->counting()
, invoking a callback with the number of replacements performed #90replace()->exactly()
, validating that exactly this many replacements were performed #90replace()->atLeast()
, validating that at least this many replacements were performed #90replace()->atMost()
, validating that at most this many replacements were performed #90pattern()->prune()
which removes every occurrence of a pattern from subject (identical to remove()->all()
)Other:
PatternStructureException
which can be used to catch exceptions for errors solely in pattern
structure (recursion, backtracking, jit limit).The detailed list of changes is in ChangeLog.md.
See ya later, aligator!
😎 T-Regx The Dinosaur is really proud to announce its eighth beta version! Despite the beta suffix, it's 100% suitable for production use. This time, we finally add support for PHP8. It's not just updating the dev-dependencies
versions. Argument errors and exceptions in PHP change with version PHP8, we needed to handle them properly, so the API of T-Regx stays the same. We would hate for T-Regx users to see irregularities when they update their PHP versions from 7.4 to 8.0.
The detailed list of changes is in ChangeLog.md.
The detailed list of changes is also in ChangeLog.md.
Rawrrrr!
😎 T-Regx The Dinosaur is really proud to announce its ninth beta version! This time we fixed filtering items in regular matching as well as fluent()
/asInt()
/asArray()
chains.
The detailed list of changes is in ChangeLog.md.
pattern()->match()->filter()
is renamed to remaining()
.MatchPattern
with remaining()
, consecutive Detail.index()
will no longer be reindexed, they will preserve the index()
they had had before remaining()
.match()->fluent()->filter()
no longer reindexes values. To reindex, use values()
.fluent()->flatMap()->first()
would return the array
, instead of the first elementpattern()->match()->filter()
which returns only matches allowed by the predicate.pattern()->match()->group()->asInt()
pattern()->match()->fluent()->filter()->first()
first calls preg_match()
, and if that result doesn't match
the predicate, then it calls preg_match_all()
.The detailed list of changes is also in ChangeLog.md.
Rawrrrr!
😎 T-Regx The Dinosaur is really proud to announce its tenth beta version! This time we fixed a lot of bugs and mistakes, and we added implicit all()
with replacing.
The detailed list of changes is in ChangeLog.md.
DetailGroup
to Group
ReplaceDetailGroup
to ReplaceGroup
BaseDetailGroup
to CapturingGroup
pattern()->replace()
without all()
/first()
/only()
, implicitly assumes all()
"group\n"
used to be considered valid, now it's correctly being treated as invalid.ReplaceMatch
is now a class, not an interface."Foo\n"
, instead of
"Foo
"
group()->fluent()
#93The detailed list of changes is also in ChangeLog.md.
Rawrrrr!
😎 T-Regx The Dinosaur is really proud to announce its eleventh version! We simplified interface of templates and builders, as well as unified Pattern
/PatternImpl
and PatternInterface
. We also added Pcre
facade, allowing to read the exact version of PCRE used, regardless of PHP version.
The detailed list of changes is in ChangeLog.md.
Detail.usingDuplicateName().get()
#101Detail.usingDuplicateName().matched()
#101Pattern:template()->literal(string)
now accepts string argument, allowing for inserting arbitrary strings into the pattern.Pattern::builder()
, which works similarly to how PatternBuilder::builder()
worked.Pattern::literal()
which creates an instance of a pattern with which matches an arbitrary string exactly, even when x
(EXTENDED
) flag is used. To add in-pattern structures, like ^
or $
, use Pattern::template()->literal()
.Pattern::template()->literal()
, which is a shorthand for Pattern::template()->builder()->literal()->build()
.Pattern::template()->mask()
, which is a shorthand for Pattern::template()->builder()->mask()->build()
.PatternInterface
to string results in a delimited patternPcre
version helpermatch()->getIterator()
no longer preserves the keys of values (like all()
)match()->group()->getIterator()
no longer preserves the keys of values (like all()
)Pattern::format()
to Pattern::mask()
Pattern::builder()->format()
to Pattern::builder()->mask()
Pattern::template()->format()
to Pattern::template()->mask()
Pattern::template()->formatting()
to Pattern::template()->builder()->mask()
literal()
now requires argument '&'
, to escape &
in-pattern tokenPatternBuilder::builder()
. Use Pattern::builder()
PatternBuilder::compose()
. Use Pattern::compose()
FormatMalformedPatternException
to MaskMalformedPatternException
PatternInterface
. Now class Pattern
is both an instance of a pattern, as well as a static-factory, i.e. Pattern::of()
/Pattern::inject()
.Pattern::template()
quoted values incorrectly, when delimiter other than /
or %
was chosen.The detailed list of changes is also in ChangeLog.md.
Rawrrrr!
😎 T-Regx The Dinosaur is really proud to announce its twelfthversion! We found loose approach to @
placeholders in prepared patterns, so we had to create a dedicated regular patterns parses that works with PCRE7, PCRE8, PCRE9 and PCRE10 instroduced in PHP8 and late PHP 7.4. Using the pattern, we can distinguish @
as literal (where it can be injected with values), or in character class, quotes or comments ([@]
, \Q@\E
and #@\n
, etc.) We also found that bind()
method failed to fulfill its intented purpose, so it was removed from the library, however template()
and inject()
remain in the library. Also, also we also strictened the rules of pattern()->forArray()
.
The detailed list of changes is in ChangeLog.md.
[@]
, \Q@\E
, \@
, \c@
and
others, like comment groups and comments in extended mode.[@]
would be injected. Now it's treated as "@"
character-class.\Q@\E
would be injected. Now it's treated as @
literal.\c@
would be injected. Now it's \c@
control character.#@\n
would be injected. Now, if x
flag is used (globally, or as a subpattern), then it's
treated as @
comment.(?#@)
would be injected. Now it's treated as @
comment.\@
would be treated as @
literal. This remains unchanged.&
in templates, use @
.Pattern::template()->builder()
. Use Pattern::template()
now.Pattern::bind()
. Use Pattern::inject()
or Pattern::template()->literal()
.Pattern::prepare()
. Use Pattern::inject()
.Pattern::pcre()->bind()
.Pattern::pcre()->prepare()
.Pattern::template()->bind()
.ValidPattern.isValid()
on PHP 8.1.The detailed list of changes is also in ChangeLog.md.
Rawrrrr!
😎 T-Regx The Dinosaur is really proud to announce its release 0.13.4
! We're coming to giga-big-release of 1.0.0
with big steps! From the last 0.12.0
release, we put more effort on rewriting the integer parsing, group building and more through exceptions in T-Regx.
Here's a summary of changes from 0.13.0
, 0.13.1
, 0.13.2
, 0.13.3
and in 0.13.4
.
The detailed list of changes is in ChangeLog.md.
toInt()
/asInt()
/isInt()
assumed the numerical string was always in base 10, before mapping to int
. Now, the base is passed in as an optional arugment (e.g. asInt(2)
), and the default value of the argument is 10
. Allowed base are 2
- 36
, and allowed digits are /[0-9a-z]/i
(depending on the base).toInt()
/asInt()
now throw either NumberFormatException
(as before), or NumberOverflowException
, if number is well formatted, but exeeds integer size on a given architecture.match()->asArray()
, because Detail.group()
and Detail.namedGroup()
are better suited for this job.pattern()->forArray()
is now strict by default.pattern()->remove()->all()
/remove()->first()
, because removing single occurrance felt weird. Now use pattern()->prune()
.filter()
and remaining()
would leave keys in the resulting array unchagnes (as if they treated array
as dictionary/map). Now the keys are now re-indexed (as if they treat array
as list). To make use of keys, use flatMap()
/flatMapAssoc()
or groupBy()
/groupByCallback()
.fluent()->first()
, where sometimes a silence false-negative with group being missing slipped by us. Exception GroupNotMatched
was thrown, where in reallity NonexistentGroup
should have been thorwn.match()->asInt()->keys()->first()
malformed integers didn't throw NumberFormatException
The detailed list of changes is also in ChangeLog.md.
Rawrrrr!