All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.search.StrParser Maven / Gradle / Ivy

There is a newer version: 9.6.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.search;

import java.util.Locale;

/**
   * Simple class to help with parsing a string.
   * Note: This API is experimental and may change in non backward-compatible ways in the future
   */
  public class StrParser {
    public String val;
    public int pos;
    public int end;

    public StrParser(String val) {
      this(val, 0, val.length());
    }

    public StrParser(String val, int start, int end) {
      this.val = val;
      this.pos = start;
      this.end = end;
    }

    public void eatws() {
      while (pos < end && Character.isWhitespace(val.charAt(pos))) pos++;
    }

    public char ch() {
      return pos < end ? val.charAt(pos) : 0;
    }

    public void skip(int nChars) {
      pos = Math.max(pos + nChars, end);
    }

    public boolean opt(String s) {
      eatws();
      int slen = s.length();
      if (val.regionMatches(pos, s, 0, slen)) {
        pos += slen;
        return true;
      }
      return false;
    }

    public boolean opt(char ch) {
      eatws();
      if (pos < end && val.charAt(pos) == ch) {
        pos++;
        return true;
      }
      return false;
    }


    public void expect(String s) throws SyntaxError {
      eatws();
      int slen = s.length();
      if (val.regionMatches(pos, s, 0, slen)) {
        pos += slen;
      } else {
        throw new SyntaxError("Expected '" + s + "' at position " + pos + " in '" + val + "'");
      }
    }

    public float getFloat() {
      eatws();
      char[] arr = new char[end - pos];
      int i;
      for (i = 0; i < arr.length; i++) {
        char ch = val.charAt(pos);
        if ((ch >= '0' && ch <= '9')
                || ch == '+' || ch == '-'
                || ch == '.' || ch == 'e' || ch == 'E'
                ) {
          pos++;
          arr[i] = ch;
        } else {
          break;
        }
      }

      return Float.parseFloat(new String(arr, 0, i));
    }

    public Number getNumber() {
      eatws();
      int start = pos;
      boolean flt = false;

      while (pos < end) {
        char ch = val.charAt(pos);
        if ((ch >= '0' && ch <= '9') || ch == '+' || ch == '-') {
          pos++;
        } else if (ch == '.' || ch =='e' || ch=='E') {
          flt = true;
          pos++;
        } else {
          break;
        }
      }

      String v = val.substring(start,pos);
      if (flt) {
        return Double.parseDouble(v);
      } else {
        return Long.parseLong(v);
      }
    }

    public double getDouble() {
      eatws();
      char[] arr = new char[end - pos];
      int i;
      for (i = 0; i < arr.length; i++) {
        char ch = val.charAt(pos);
        if ((ch >= '0' && ch <= '9')
                || ch == '+' || ch == '-'
                || ch == '.' || ch == 'e' || ch == 'E'
                ) {
          pos++;
          arr[i] = ch;
        } else {
          break;
        }
      }

      return Double.parseDouble(new String(arr, 0, i));
    }

    public int getInt() {
      eatws();
      char[] arr = new char[end - pos];
      int i;
      for (i = 0; i < arr.length; i++) {
        char ch = val.charAt(pos);
        if ((ch >= '0' && ch <= '9')
                || ch == '+' || ch == '-'
                ) {
          pos++;
          arr[i] = ch;
        } else {
          break;
        }
      }

      return Integer.parseInt(new String(arr, 0, i));
    }


    public String getId() throws SyntaxError {
      return getId("Expected identifier");
    }

    public String getId(String errMessage) throws SyntaxError {
      eatws();
      int id_start = pos;
      char ch;
      if (pos < end && (ch = val.charAt(pos)) != '$' && Character.isJavaIdentifierStart(ch)) {
        pos++;
        while (pos < end) {
          ch = val.charAt(pos);
//          if (!Character.isJavaIdentifierPart(ch) && ch != '.' && ch != ':') {
          if (!Character.isJavaIdentifierPart(ch) && ch != '.') {
            break;
          }
          pos++;
        }
        return val.substring(id_start, pos);
      }

      if (errMessage != null) {
        throw new SyntaxError(errMessage + " at pos " + pos + " str='" + val + "'");
      }
      return null;
    }

    public String getGlobbedId(String errMessage) throws SyntaxError {
      eatws();
      int id_start = pos;
      char ch;
      if (pos < end && (ch = val.charAt(pos)) != '$' && (Character.isJavaIdentifierStart(ch) || ch=='?' || ch=='*')) {
        pos++;
        while (pos < end) {
          ch = val.charAt(pos);
          if (!(Character.isJavaIdentifierPart(ch) || ch=='?' || ch=='*') && ch != '.') {
            break;
          }
          pos++;
        }
        return val.substring(id_start, pos);
      }

      if (errMessage != null) {
        throw new SyntaxError(errMessage + " at pos " + pos + " str='" + val + "'");
      }
      return null;
    }

    /**
     * Skips leading whitespace and returns whatever sequence of non 
     * whitespace it can find (or hte empty string)
     */
    public String getSimpleString() {
      eatws();
      int startPos = pos;
      char ch;
      while (pos < end) {
        ch = val.charAt(pos);
        if (Character.isWhitespace(ch)) break;
        pos++;
      }
      return val.substring(startPos, pos);
    }

    /**
     * Sort direction or null if current position does not indicate a 
     * sort direction. (True is desc, False is asc).  
     * Position is advanced to after the comma (or end) when result is non null 
     */
    public Boolean getSortDirection() throws SyntaxError {
      final int startPos = pos;
      final String order = getId(null);

      Boolean top = null;

      if (null != order) {
        final String orderLowerCase = order.toLowerCase(Locale.ROOT);
        if ("desc".equals(orderLowerCase) || "top".equals(orderLowerCase)) {
          top = true;
        } else if ("asc".equals(orderLowerCase) || "bottom".equals(orderLowerCase)) {
          top = false;
        }

        // it's not a legal direction if more stuff comes after it
        eatws();
        final char c = ch();
        if (0 == c) {
          // :NOOP
        } else if (',' == c) {
          pos++;
        } else {
          top = null;
        }
      }

      if (null == top) pos = startPos; // no direction, reset
      return top;
    }

    // return null if not a string
    public String getQuotedString() throws SyntaxError {
      eatws();
      char delim = peekChar();
      if (!(delim == '\"' || delim == '\'')) {
        return null;
      }
      int val_start = ++pos;
      StringBuilder sb = new StringBuilder(); // needed for escaping
      for (; ;) {
        if (pos >= end) {
          throw new SyntaxError("Missing end quote for string at pos " + (val_start - 1) + " str='" + val + "'");
        }
        char ch = val.charAt(pos);
        if (ch == '\\') {
          pos++;
          if (pos >= end) break;
          ch = val.charAt(pos);
          switch (ch) {
            case 'n':
              ch = '\n';
              break;
            case 't':
              ch = '\t';
              break;
            case 'r':
              ch = '\r';
              break;
            case 'b':
              ch = '\b';
              break;
            case 'f':
              ch = '\f';
              break;
            case 'u':
              if (pos + 4 >= end) {
                throw new SyntaxError("bad unicode escape \\uxxxx at pos" + (val_start - 1) + " str='" + val + "'");
              }
              ch = (char) Integer.parseInt(val.substring(pos + 1, pos + 5), 16);
              pos += 4;
              break;
          }
        } else if (ch == delim) {
          pos++;  // skip over the quote
          break;
        }
        sb.append(ch);
        pos++;
      }

      return sb.toString();
    }

    // next non-whitespace char
    public char peek() {
      eatws();
      return pos < end ? val.charAt(pos) : 0;
    }

    // next char
    public char peekChar() {
      return pos < end ? val.charAt(pos) : 0;
    }

    @Override
    public String toString() {
      return "'" + val + "'" + ", pos=" + pos;
    }

  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy