Class Parsers

java.lang.Object
com.google.common.labs.parse.Parsers

public final class Parsers extends Object
More advanced composite parsers in addition to the core parsers provided by Parser.
Since:
10.8
  • Field Details

    • UNSIGNED_INTEGER

      public static final Parser<String> UNSIGNED_INTEGER
      Parses unsigned decimal integer numbers, e.g., 15, 0.

      To support signs, you can compose it like:

      
       Parser<Long> signed = sequence(
           one('-').thenReturn(-1).orElse(1), UNSIGNED_INTEGER.map(Long::parseLong),
           (sign, num) -> sign * num);
       
    • UNSIGNED_DECIMAL

      public static final Parser<String> 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

      public static final Parser<Double> 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 as BigDecimal:

      
       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., .5 or 5.) are not allowed, as per the JSON standard.

    • DURATION

      public static final Parser<Duration> DURATION
      Parses duration in the shorthand format of 1.5h, 30d, 10m30s etc.

      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 days
      • d (days) - treated as exactly 24 hours
      • h (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

      public static final Parser<Character> 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

      public static final Parser<Integer> CODE_POINT
      Parses an 8-digit hex Unicode code point (such as those following \U in string escapes).

      The parsed integer is guaranteed to be a valid Unicode code point (between 0 and 0x10FFFF).

      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

      public static Parser<String> regex(@CompileTimeConstant String pattern)
      Returns a leaf-level parser that matches an atomic regular expression pattern. 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"); // => true
       

      Useful 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 declarative Parser API 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 Parser combinator API (using methods like followedBy(), sequence(), anyOf(), etc.) and only use regex on 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 Reader input 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 throw UnsupportedOperationException when calling Parser.parseToStream(Reader) or Parser.probe(Reader), because Java regex requires the input to be fully loaded into memory, defeating the purpose of lazy loading from Reader - you might as well just explicitly load into a String before parsing.

      The pattern string is validated at compile-time by the mug-errorprone (v10.9+) compiler plugin.

      NOTE that this method internally compiles the pattern so you should almost always pre-create and reuse the returned Parser object instead of calling regex(pattern) in the inner loop or on-the-fly.

      Throws:
      IllegalArgumentException - if the pattern is invalid or contains forbidden features.
      Since:
      10.9