krabka-java-regex
Java's java.util.regex in Rust: Pattern.compile, Matcher.matches(), String.replaceAll and String.replaceFirst, answered as JDK 25 answers them.
Part of Krabka, a Rust implementation of Apache Kafka.
Overview
Three Apache Kafka configs take a Java regular expression: ssl.principal.mapping.rules (KIP-371), the Kerberos auth_to_local rules, and the match patterns of a KIP-714 CLIENT_METRICS subscription. A rule that matches differently from Java maps a principal to another name, or selects other clients, so krabka-broker needs Java's answer exactly. This crate gives it. It rewrites the Java pattern for fancy-regex, and runs the constructs fancy-regex reads otherwise on a backtracking matcher of its own.
Features
JavaPattern::matchesisMatcher.matches(): some way of matching spans the whole input, through backtracking and lazy quantifiers.JavaPattern::replaceisreplaceAllorreplaceFirst. Its matches areMatcher.find's, empty matches and\Gincluded, and its replacement syntax isappendReplacement's:$n,${name}and\x.- Java's reading of the syntax:
- the ASCII
\w,\d,\s,\band POSIX classes, and their Unicode forms under(?U) .,$,^and\Zwith Java's line terminators, under(?s),(?m)and(?d)\h,\vand\R- ASCII case folding under
(?i), and Java's own Unicode case folding under(?iu) - class intersection with
&& \Q…\Eand(?x)comments
- the ASCII
- Java's matcher, where
fancy-regexdiffers:- backreferences under a case flag
\Rgiving back the\nof\r\n- groups that keep their text after a look-around, an atomic group, a possessive quantifier or an iteration of a repeated group
- empty iterations of a repeated group: kept by Java's
Loop, and skipped by itsGroupCurlypast the least count \Gafter an empty match- a look-behind over a char past U+FFFF, whose starts Java counts in UTF-16 units, one of them between the two units of the char
- Java's patterns that
fancy-regexcannot compile, answered by the backtracking matcher: a look-behind that is not of one length with\R, a look-around, an atomic group or a group in it, such as(?<=\R?x)y, and a counted repeat too large for theregexcrate to build, such asx{1,1000000000}, which the matcher counts. JavaPattern::compilerefuses whatPattern.compilerefuses: duplicate group names, a dangling quantifier, a backwards repeat range, an unknown property name, a look-behind with no obvious maximum length, and the rest. It also refuses the few patterns it cannot read as Java does, rather than match them another way: Unicode blocks,\X,\N{name}, a quantified look-around, a backreference to a group the pattern does not have, and a look-behind whose maximum length overflows Java'sintso that it tries fewer starts. The crate docs list them under Limits, with the input limit that a few such look-behinds take.- A search takes at most 1,000,000 backtracking steps. One past the limit is an error, not a no match, so a mapping rule cannot fall through to the next rule when Java would have applied it. The backtracking matcher keeps its own stack, so a long input cannot overflow the thread's.
Usage
use JavaPattern;
Documentation
License
Apache-2.0. Derivative work of Apache Kafka; see NOTICE.