Class Pattern

java.lang.Object
dev.gmitch215.bytebox.regex.Pattern

public final class Pattern extends Object
A compiled pattern, standing in for java.util.regex.Pattern.

The compiler substitutes java.util.regex.Pattern for this one, so a project matching the ordinary way works unchanged. Underneath it is the platform's own regular expressions, which the isolate already has: the class library's pattern compiler and matcher measure 68 KB of WebAssembly after compression, and V8 has an engine already.

The pattern is rewritten rather than passed through, because the two syntaxes agree about most things and disagree about a few that look identical - Translate lists them. What has no exact equivalent is refused by Pattern.compile, when the program runs, with a PatternSyntaxException naming it, so a pattern either means here what it means on a JVM or it does not compile. Refused: a flag written anywhere but the start of the pattern, \G, \X, and every character property except the POSIX names and the Unicode blocks of the basic multilingual plane.

A flag group that opens the pattern, such as (?i), is read as the flags it sets, and flags() reports them the way a JVM does.

An atomic group, (?>X), and a possessive quantifier, X*+, are written as a lookahead that captures what the atom takes and a backreference to it, which matches the same text and cannot be backtracked into. The group numbers, names and replacement references a caller uses are the ones written in the pattern. Four things are refused. Inside a lookbehind they are refused, because the platform reads a lookbehind backwards. A backreference to a group that is not open yet is refused, because a JVM never matches it and the platform would. A backreference inside the group it names, as in (a\1), is refused: a JVM reads that group as not closed, so the reference never matches on the first pass and reads the previous pass's text on later ones, where the platform reads it as the empty string. And a capturing group inside the atom is refused, because after an attempt that took the atom and was abandoned a JVM keeps the span the group had there where the platform has none. A group beside the atom or around it is read as written. Neither construct makes a pattern cheaper to run: the engine still backtracks through everything else, and a pattern that backtracks badly runs far slower here than on a JVM.

A class inside a class, [a[b]], an intersection, [a-z&&[^b]], a negated block, \P{InGreek}, and a character above U+FFFF inside a class, written as itself or by \x{1F600}, are written for the v flag, which reads the pattern as code points where the platform otherwise reads UTF-16 units, so the flag is used for a pattern that has one of them and for no other. Without it a negated block would match each half of a character above U+FFFF by itself. Such a pattern is refused together with UNICODE_CASE, where the flag would change how case folds. A JVM also starts a search in the middle of a surrogate pair: after an empty match, from find(int), and at every UTF-16 unit when nothing in the pattern can take half of a pair. An engine that reads code points cannot start there, so the matcher makes that try itself on the text from the middle of the pair, and finds what a JVM finds. A hyphen, an ampersand or an escape that a JVM reads in a way no exact rewrite follows is refused, naming it.

The escapes that stand for one character are read as a JVM reads them and written out plainly: \x{h...h}, \0n, \0nn, \0mnn and \cX, which the platform reads as something else or not at all, and a surrogate pair written as two u escapes. One a JVM refuses (a malformed hexadecimal or octal escape, a letter after a backslash that means nothing, \k without a group of that name) is refused. Under COMMENTS a JVM skips whitespace and comments wherever it reads the next character of such an escape, so whitespace inside one is refused.

A pattern for the platform's own mode reads UTF-16 units, so ., a negated class such as [^x], the escapes that mean everything but something (\S, \H, \V, \W, \D, \P{Alpha}), a class that reaches the surrogates and a lone surrogate would take half of a character above U+FFFF where a JVM takes the whole. Over text with no such character they are exact, and over text with one, matcher(java.lang.CharSequence) makes the matcher run a second source of the same pattern written for the v flag, with the caveats of that flag above. Under UNICODE_CASE there is no second source, so matcher refuses text that holds such a character, with an UnsupportedOperationException naming the construct, when the pattern has one of them. A lookbehind holding one of them is sized by a JVM in UTF-16 units, so a lookbehind of several characters can differ over such text.

CASE_INSENSITIVE on its own folds only ASCII, as it does on a JVM: each letter is written as the pair of its cases, and the platform's folding, which reaches across the whole of Unicode, is not used. A backreference cannot be written that way, since it stands for whatever its group took, so a pattern with one is refused under CASE_INSENSITIVE without UNICODE_CASE. A hyphen beside a set or a finished range inside a class cannot be written as a pair and keeps the platform's folding, so a non-ASCII letter folds there where a JVM's does not.

With UNICODE_CASE the platform's folding is used. It agrees with a JVM except for a few dozen characters: the long s, the Kelvin, ohm and angstrom signs, the dotted and dotless i, the capital sharp s, the capital theta symbol, and the Greek letters with an iota subscript and their titlecase forms. A JVM folds each of those to its partner and the platform does not.

Since:
1.0.0
  • Field Details

    • CASE_INSENSITIVE

      public static final int CASE_INSENSITIVE
      Fold case when matching, across ASCII unless UNICODE_CASE is set too.
      See Also:
    • COMMENTS

      public static final int COMMENTS
      Treat whitespace and # comments in the pattern as nothing.
      See Also:
    • MULTILINE

      public static final int MULTILINE
      Let ^ and $ match at every line.
      See Also:
    • LITERAL

      public static final int LITERAL
      Treat the pattern as a literal.
      See Also:
    • DOTALL

      public static final int DOTALL
      Let . match a line terminator.
      See Also:
    • UNICODE_CASE

      public static final int UNICODE_CASE
      Fold case across the whole of Unicode, with the platform's own folding.
      See Also:
    • CANON_EQ

      public static final int CANON_EQ
      Normalise before matching, which is refused.
      See Also:
    • UNIX_LINES

      public static final int UNIX_LINES
      Treat only \n as a line terminator.
      See Also:
    • UNICODE_CHARACTER_CLASS

      public static final int UNICODE_CHARACTER_CLASS
      Make the predefined classes match across the whole of Unicode, which is refused.
      See Also:
  • Method Details

    • compile

      public static Pattern compile(String pattern)
      Compiles a pattern.
      Parameters:
      pattern - the pattern
      Returns:
      the compiled pattern
      Throws:
      PatternSyntaxException - when the pattern is not one, or uses something with no exact equivalent here
    • compile

      public static Pattern compile(String pattern, int flags)
      Compiles a pattern with flags.
      Parameters:
      pattern - the pattern
      flags - the flags, combined with |
      Returns:
      the compiled pattern
      Throws:
      PatternSyntaxException - when the pattern is not one, or uses something with no exact equivalent here
    • matches

      public static boolean matches(String pattern, CharSequence input)
      Whether a whole input matches a pattern, compiling it each time.
      Parameters:
      pattern - the pattern
      input - what to match
      Returns:
      whether it matches
    • quote

      public static String quote(String text)
      A pattern that matches a literal.
      Parameters:
      text - the literal
      Returns:
      a pattern matching exactly it
    • matcher

      public Matcher matcher(CharSequence input)
      A matcher over an input.
      Parameters:
      input - what to search
      Returns:
      the matcher
      Throws:
      UnsupportedOperationException - when the input holds a character above U+FFFF and the pattern holds something that would read half of one, with UNICODE_CASE
    • pattern

      public String pattern()
      Returns the pattern as written.
      Returns:
      the pattern as written
    • flags

      public int flags()
      Returns the flags it was compiled with, with any flag group that opens the pattern applied.
      Returns:
      the flags it was compiled with, with any flag group that opens the pattern applied
    • toString

      public String toString()
      Returns the pattern as written.
      Overrides:
      toString in class Object
      Returns:
      the pattern as written
    • split

      public String[] split(CharSequence input)
      Splits an input around every match.
      Parameters:
      input - what to split
      Returns:
      the pieces
    • split

      public String[] split(CharSequence input, int limit)
      Splits an input around every match.
      Parameters:
      input - what to split
      limit - how many pieces at most, zero for no limit with trailing empties dropped, negative for no limit with them kept
      Returns:
      the pieces
    • asPredicate

      public Predicate<String> asPredicate()
      Returns a predicate answering whether the pattern is found anywhere in a string.
      Returns:
      a predicate answering whether the pattern is found anywhere in a string
    • asMatchPredicate

      public Predicate<String> asMatchPredicate()
      Returns a predicate answering whether the pattern matches a whole string.
      Returns:
      a predicate answering whether the pattern matches a whole string
    • splitAsStream

      public Stream<String> splitAsStream(CharSequence input)
      The pieces an input splits into, as a stream.
      Parameters:
      input - what to split
      Returns:
      the pieces
    • namedGroups

      public Map<String,Integer> namedGroups()
      Returns every named group, in the order the pattern declares them.
      Returns:
      every named group, in the order the pattern declares them