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
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    Provides helpers to left-factor common prefixes followed by one or multiple optional suffixes.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final Parser<Character>
    Parses a 4-digit hex BMP code unit.
    static final Parser<Integer>
    Parses an 8-digit hex Unicode code point (such as those following \U in string escapes).
    static final Parser<Duration>
    Parses duration in the shorthand format of 1.5h, 30d, 10m30s etc.
    static final Parser<Double>
    Parses double-precision numbers that support scientific notation, conforming to RFC 8259 (JSON spec).
    static final Parser<String>
    Parses unsigned decimal point numbers, e.g., 1.23, 0.0, 15, 0.
    static final Parser<String>
    Parses unsigned decimal integer numbers, e.g., 15, 0.
  • Method Summary

    Modifier and Type
    Method
    Description
    static Parser<String>
    regex(String pattern)
    Returns a leaf-level parser that matches an atomic regular expression pattern.
    static <T> Parser<T>
    regex(String pattern, MapFrom3<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 3 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, MapFrom4<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 4 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, MapFrom5<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 5 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, MapFrom6<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 6 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, MapFrom7<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 7 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, MapFrom8<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 8 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, BiFunction<? super String, ? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the 2 captured group values using mapper.
    static <T> Parser<T>
    regex(String pattern, Function<? super String, ? extends T> mapper)
    Returns a leaf-level parser that matches the given pattern and transforms the captured group value using mapper.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • 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.

      If you need to extract values from capturing groups in the matched regex, use regex(String, Function) or other group-mapping overloads (such as regex(String, BiFunction)) instead.

      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
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, Function<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the captured group value using mapper.

      For example, to extract the area code from a phone number:

      
       Parser<Integer> areaCode = regex("\\((\\d{3})\\) \\d{3}-\\d{4}", Integer::parseInt);
       

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 1 capturing group or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, BiFunction<? super String, ? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 2 captured group values using mapper.

      For example, to extract the area code and optional extension from a phone number:

      
       Parser<PhoneNumber> phoneNumber = regex(
           "\\((?<areaCode>\\d{3})\\) \\d{3}-\\d{4}(?: x(?<extension>\\d+))?",
           (areaCode, extension) -> new PhoneNumber(areaCode, extension));
       

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+. For example, the following will fail compilation:

      
       Parser<PhoneNumber> phoneNumber = regex(
           "\\((?<areaCode>\\d{3})\\) \\d{3}-\\d{4}(?: x(?<extension>\\d+))?",
           (extension, areaCode) -> ...); // Compile error: parameters out of order
       
      Throws:
      IllegalArgumentException - if the regex does not have exactly 2 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, MapFrom3<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 3 captured group values using mapper.

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 3 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, MapFrom4<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 4 captured group values using mapper.

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 4 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, MapFrom5<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 5 captured group values using mapper.

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 5 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, MapFrom6<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 6 captured group values using mapper.

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 6 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, MapFrom7<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 7 captured group values using mapper.

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 7 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0
    • regex

      public static <T> Parser<T> regex(@CompileTimeConstant String pattern, MapFrom8<? super String, ? extends T> mapper)
      Returns a leaf-level parser that matches the given pattern and transforms the 8 captured group values using mapper.

      Capturing groups start from group 1; group 0 (the top-level full match) is not passed to the mapper. If you only need the top-level match, use regex(String); if you need both the entire match and nested groups, wrap the entire pattern in parentheses (e.g. "((foo)(bar))"). Alternatively, calling .source() on the returned parser returns the full matched substring.

      Nested capturing groups are fully supported (ordered by opening parenthesis). Optional groups (such as (?:-(\d+))?) and alternations (such as (\d+)|([a-z]+)) will pass null to the mapper if that group was not matched.

      If named capturing groups (such as "(?<name>...)") are used, their names are checked at compile time against lambda parameter names (or method reference parameters) with mug-errorprone 11.0+.

      Throws:
      IllegalArgumentException - if the regex does not have exactly 8 capturing groups or is invalid / contains forbidden features.
      Since:
      11.0