Class Parsers
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classProvides helpers to left-factor common prefixes followed by one or multiple optional suffixes. -
Field Summary
FieldsModifier and TypeFieldDescriptionParses a 4-digit hex BMP code unit.Parses an 8-digit hex Unicode code point (such as those following\Uin string escapes).Parses duration in the shorthand format of1.5h,30d,10m30setc.Parses double-precision numbers that support scientific notation, conforming to RFC 8259 (JSON spec).Parses unsigned decimal point numbers, e.g.,1.23,0.0,15,0.Parses unsigned decimal integer numbers, e.g.,15,0. -
Method Summary
-
Field Details
-
UNSIGNED_INTEGER
-
UNSIGNED_DECIMAL
Parses unsigned decimal point numbers, e.g.,1.23,0.0,15,0.To support signs, you can compose it like:
Parser<Double> signedDecimal = sequence( one('-').thenReturn(-1).orElse(1), UNSIGNED_DECIMAL.map(Double::parseDouble), (sign, num) -> sign * num); -
SIGNED_DOUBLE
Parses double-precision numbers that support scientific notation, conforming to RFC 8259 (JSON spec).E.g.,
123,-0.5,1e10,-1.23e+4,0.0e-5.The input string is parsed into a
Double. You can also call.source()if you prefer to obtain the raw matched string or parse into a different type such asBigDecimal:Parser<BigDecimal> bigDecimal = Parsers.SIGNED_DOUBLE.source().map(BigDecimal::new);Note that leading plus signs (e.g.,
+1), leading zeros on integers (e.g.,05), and missing integer or fractional parts (e.g.,.5or5.) are not allowed, as per the JSON standard. -
DURATION
Parses duration in the shorthand format of1.5h,30d,10m30setc.Matches one or more unit specs consisting of a positive decimal number followed by a unit suffix. For example:
"30s"->30 seconds"2h30m"->2 hours and 30 minutes"1w2d"->9 days (1 week + 2 days)"1.5h"->1 hour and 30 minutes
Supported units:
w(weeks) - treated as exactly 7 daysd(days) - treated as exactly 24 hoursh(hours)m(minutes)s(seconds)ms(milliseconds)us(microseconds)ns(nanoseconds)
Note:
- The duration components must be specified in strictly descending order of unit size
(e.g.,
"1d2h"is allowed, but"2h1d"or"1d1d"are not). - Only the last component can contain a decimal point (e.g.,
"1.5h"or"1h2.5m"are allowed, but"1.5h2m"is not). - Negative values (e.g.,
"-2s") are not supported.
-
BMP_CODE_UNIT
Parses a 4-digit hex BMP code unit.You can use it together with
Parser.quotedByWithEscapes()to parse unicode escapes like:Parser.quotedByWithEscapes('"', '"', Parser.one('u').then(BMP_CODE_UNIT).map(String::valueOf)); -
CODE_POINT
Parses an 8-digit hex Unicode code point (such as those following\Uin string escapes).The parsed integer is guaranteed to be a valid Unicode code point (between
0and0x10FFFF).You can use it together with
Parser.quotedByWithEscapes()to parse unicode escapes like:Parser<String> quotedStringWithUnicodeEscape = Parser.quotedByWithEscapes( '"', '"', Parser.one('U').then(CODE_POINT).map(Character::toString)); quotedStringWithUnicodeEscape.parse("\\U0001F600"); // returns "😀"
-
-
Method Details
-
regex
Returns a leaf-level parser that matches an atomic regular expressionpattern. For example, you could define a parser for US phone numbers using:Parser<String> usPhoneNumber = Parsers.regex("\\(\\d{3}\\)\\d{3}-\\d{4}"); usPhoneNumber.matches("(123)456-7890"); // => trueUseful when defining a compact, yet composite regex pattern that may otherwise require verbose boilerplate of
sequence(),anyOf()calls composed together. That said, refrain from creating complex regex patterns, and prefer using the declarativeParserAPI unless it's too verbose.WARNING: ReDoS Vulnerabilities & Disastrous Backtracking
Using regular expressions exposes the application to Regular Expression Denial of Service (ReDoS) attacks. In many regex engines (including
Pattern), even "simple" patterns can cause exponential backtracking if matched against malicious inputs designed to trigger worst-case paths.For example, the pattern
(a+)+or(a|ab)+can easily freeze a thread or crash a service with CPU exhaustion when attempting to match a string like"aaaaaaaaaaaaaaaaaaaaaaaaaaaa!". See the OWASP ReDoS Attack Reference for a detailed analysis of this issue.To avoid ReDoS and keep parsing execution linear and safe, prefer the declarative, backtracking-free
Parsercombinator API (using methods likefollowedBy(),sequence(),anyOf(), etc.) and only useregexon trusted input (such as a config file, command line tool etc).The pattern must be a compile-time constant, must not match the empty string, and must not contain anchors (like
^,$), lookarounds (like(?=...)), or backreferences (like\1).The returned parser supports parsing from a
Readerinput only if the regex has an upper bound in the match size (e.g.[a-z]{3}or(abc|d)). Regex patterns with unbounded match size (e.g.[a-z]+) will throwUnsupportedOperationExceptionwhen callingParser.parseToStream(Reader)orParser.probe(Reader), because Java regex requires the input to be fully loaded into memory, defeating the purpose of lazy loading fromReader- you might as well just explicitly load into aStringbefore parsing.The
patternstring is validated at compile-time by themug-errorprone(v10.9+) compiler plugin.NOTE that this method internally compiles the
patternso you should almost always pre-create and reuse the returnedParserobject instead of callingregex(pattern)in the inner loop or on-the-fly.- Throws:
IllegalArgumentException- if the pattern is invalid or contains forbidden features.- Since:
- 10.9
-