Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed 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 com.facebook.presto.type;
 
 import org.joni.Regex;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.joni.constants.MetaChar.INEFFECTIVE_META_CHAR;
 import static org.joni.constants.SyntaxProperties.OP_ASTERISK_ZERO_INF;
 import static org.joni.constants.SyntaxProperties.OP_DOT_ANYCHAR;
 import static org.joni.constants.SyntaxProperties.OP_LINE_ANCHOR;
 
 public final class LikeFunctions
 {
     private static final Syntax SYNTAX = new Syntax(
              |  | ,
             0,
             0,
             .,
             new Syntax.MetaCharTable(
                     '\\',                           /* esc */
                     ,          /* anychar '.' */
                     ,          /* anytime '*' */
                     ,          /* zero or one time '?' */
                     ,          /* one or more time '+' */
                                /* anychar anytime */
             )
     );
 
     private LikeFunctions() {}
 
     // TODO: this should not be callable from SQL
     @ScalarFunction(value = "like", hidden = true)
     public static boolean like(@SqlType(.Slice value, @SqlType(.Regex pattern)
     {
         // Joni doesn't handle invalid UTF-8, so replace invalid characters
         byte[] bytes = value.getBytes();
         if (isAscii(bytes)) {
             return regexMatches(patternbytes);
         }
         // convert to a String and back to "fix" any broken UTF-8 sequences
         return regexMatches(patternvalue.toStringUtf8().getBytes());
     }
 
     public static Regex likePattern(@SqlType(.Slice pattern)
     {
         return likeToPattern(pattern.toStringUtf8(), '0'false);
     }
 
     @ScalarFunction
     public static Regex likePattern(@SqlType(.Slice pattern, @SqlType(.Slice escape)
     {
         return likeToPattern(pattern.toStringUtf8(), getEscapeChar(escape), true);
     }
 
     private static boolean regexMatches(Regex regexbyte[] bytes)
     {
         return regex.matcher(bytes).match(0, bytes.length.) != -1;
     }
 
     @SuppressWarnings("NestedSwitchStatement")
     private static Regex likeToPattern(String patternStringchar escapeCharboolean shouldEscape)
     {
         StringBuilder regex = new StringBuilder(patternString.length() * 2);
 
         regex.append('^');
         boolean escaped = false;
         for (char currentChar : patternString.toCharArray()) {
             if (shouldEscape && !escaped && (currentChar == escapeChar)) {
                 escaped = true;
             }
             else {
                 switch (currentChar) {
                     case '%':
                         regex.append(escaped ? "%" : ".*");
                         escaped = false;
                        break;
                    case '_':
                        regex.append(escaped ? "_" : ".");
                        escaped = false;
                        break;
                    default:
                        // escape special regex characters
                        switch (currentChar) {
                            case '\\':
                            case '^':
                            case '$':
                            case '.':
                            case '*':
                                regex.append('\\');
                        }
                        regex.append(currentChar);
                        escaped = false;
                }
            }
        }
        regex.append('$');
        byte[] bytes = regex.toString().getBytes();
        return new Regex(bytes, 0, bytes.length..);
    }
    @SuppressWarnings("NumericCastThatLosesPrecision")
    private static char getEscapeChar(Slice escape)
    {
        String escapeString = escape.toString();
        if (escapeString.isEmpty()) {
            // escaping disabled
            return (char) -1; // invalid character
        }
        if (escapeString.length() == 1) {
            return escapeString.charAt(0);
        }
        throw new IllegalArgumentException("escape must be empty or a single character: " + escapeString);
    }
    private static boolean isAscii(byte[] bytes)
    {
        for (byte b : bytes) {
            if (b < 0) {
                return false;
            }
        }
        return true;
    }
New to GrepCode? Check out our FAQ X