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.operator.scalar;
 
 
 
 
 import static com.facebook.presto.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT;
 import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
 import static com.facebook.presto.type.TypeUtils.buildStructuralSlice;
 import static java.lang.String.format;
 
 public final class RegexpFunctions
 {
     private RegexpFunctions()
     {
     }
 
     public static Regex castToRegexp(@SqlType(.Slice pattern)
     {
         Regex regex;
         try {
             // When normal UTF8 encoding instead of non-strict UTF8) is used, joni can infinite loop when invalid UTF8 slice is supplied to it.
             regex = new Regex(pattern.getBytes(), 0, pattern.length(), ...);
         }
         catch (Exception e) {
             throw new PrestoException(e);
         }
         return regex;
     }
 
     @Description("returns substrings matching a regular expression")
     @ScalarFunction
     public static boolean regexpLike(@SqlType(.Slice source, @SqlType(.Regex pattern)
     {
         Matcher m = pattern.matcher(source.getBytes());
         int offset = m.search(0, source.length(), .);
         return offset != -1;
     }
 
     @Description("removes substrings matching a regular expression")
     @ScalarFunction
     public static Slice regexpReplace(@SqlType(.Slice source, @SqlType(.Regex pattern)
     {
         return regexpReplace(sourcepattern.);
     }
 
     @Description("replaces substrings matching a regular expression by given string")
     @ScalarFunction
     public static Slice regexpReplace(@SqlType(.Slice source, @SqlType(.Regex pattern, @SqlType(.Slice replacement)
     {
         Matcher matcher = pattern.matcher(source.getBytes());
         SliceOutput sliceOutput = new DynamicSliceOutput(source.length() + replacement.length() * 5);
 
         int lastEnd = 0;
         int nextStart = 0; // nextStart is the same as lastEnd, unless the last match was zero-width. In such case, nextStart is lastEnd + 1.
         while (true) {
             int offset = matcher.search(nextStartsource.length(), .);
             if (offset == -1) {
                 break;
             }
            if (matcher.getEnd() == matcher.getBegin()) {
                nextStart = matcher.getEnd() + 1;
            }
            else {
                nextStart = matcher.getEnd();
            }
            Slice sliceBetweenReplacements = source.slice(lastEndmatcher.getBegin() - lastEnd);
            lastEnd = matcher.getEnd();
            sliceOutput.appendBytes(sliceBetweenReplacements);
            appendReplacement(sliceOutputsourcepatternmatcher.getEagerRegion(), replacement);
        }
        sliceOutput.appendBytes(source.slice(lastEndsource.length() - lastEnd));
        return sliceOutput.slice();
    }
    private static void appendReplacement(SliceOutput resultSlice sourceRegex patternRegion regionSlice replacement)
    {
        // Handle the following items:
        // 1. ${name};
        // 2. $0, $1, $123 (group 123, if exists; or group 12, if exists; or group 1);
        // 3. \\, \$, \t (literal 't').
        // 4. Anything that doesn't starts with \ or $ is considered regular bytes
        int idx = 0;
        while (idx < replacement.length()) {
            byte nextByte = replacement.getByte(idx);
            if (nextByte == '$') {
                idx++;
                if (idx == replacement.length()) { // not using checkArgument because `.toStringUtf8` is expensive
                    throw new PrestoException("Illegal replacement sequence: " + replacement.toStringUtf8());
                }
                nextByte = replacement.getByte(idx);
                int backref;
                if (nextByte == '{') { // case 1 in the above comment
                    idx++;
                    int startCursor = idx;
                    while (idx < replacement.length()) {
                        nextByte = replacement.getByte(idx);
                        if (nextByte == '}') {
                            break;
                        }
                        idx++;
                    }
                    byte[] groupName = replacement.getBytes(startCursoridx - startCursor);
                    try {
                        backref = pattern.nameToBackrefNumber(groupName, 0, groupName.lengthregion);
                    }
                    catch (ValueException e) {
                        throw new PrestoException("Illegal replacement sequence: unknown group { " + new String(groupName.) + " }");
                    }
                    idx++;
                }
                else { // case 2 in the above comment
                    backref = nextByte - '0';
                    if (backref < 0 || backref > 9) { // not using checkArgument because `.toStringUtf8` is expensive
                        throw new PrestoException("Illegal replacement sequence: " + replacement.toStringUtf8());
                    }
                    if (region.numRegs <= backref) {
                        throw new PrestoException("Illegal replacement sequence: unknown group " + backref);
                    }
                    idx++;
                    while (idx < replacement.length()) { // Adaptive group number: find largest group num that is not greater than actual number of groups
                        int nextDigit = replacement.getByte(idx) - '0';
                        if (nextDigit < 0 || nextDigit > 9) {
                            break;
                        }
                        int newBackref = (backref * 10) + nextDigit;
                        if (region.numRegs <= newBackref) {
                            break;
                        }
                        backref = newBackref;
                        idx++;
                    }
                }
                int beg = region.beg[backref];
                int end = region.end[backref];
                if (beg != -1 && end != -1) { // the specific group doesn't exist in the current match, skip
                    result.appendBytes(source.slice(begend - beg));
                }
            }
            else { // case 3 and 4 in the above comment
                if (nextByte == '\\') {
                    idx++;
                    if (idx == replacement.length()) { // not using checkArgument because `.toStringUtf8` is expensive
                        throw new PrestoException("Illegal replacement sequence: " + replacement.toStringUtf8());
                    }
                    nextByte = replacement.getByte(idx);
                }
                result.appendByte(nextByte);
                idx++;
            }
        }
    }
    @Description("string(s) extracted using the given pattern")
    @SqlType("array<varchar>")
    public static Slice regexpExtractAll(@SqlType(.Slice source, @SqlType(.Regex pattern)
    {
        return regexpExtractAll(sourcepattern, 0);
    }
    @Description("group(s) extracted using the given pattern")
    @SqlType("array<varchar>")
    public static Slice regexpExtractAll(@SqlType(.Slice source, @SqlType(.Regex pattern, @SqlType(.long groupIndex)
    {
        Matcher matcher = pattern.matcher(source.getBytes());
        validateGroup(groupIndexmatcher.getEagerRegion());
        BlockBuilder blockBuilder = .createBlockBuilder(new BlockBuilderStatus(), 32);
        int group = Ints.checkedCast(groupIndex);
        int nextStart = 0;
        while (true) {
            int offset = matcher.search(nextStartsource.length(), .);
            if (offset == -1) {
                break;
            }
            if (matcher.getEnd() == matcher.getBegin()) {
                nextStart = matcher.getEnd() + 1;
            }
            else {
                nextStart = matcher.getEnd();
            }
            Region region = matcher.getEagerRegion();
            int beg = region.beg[group];
            int end = region.end[group];
            if (beg == -1 || end == -1) {
                blockBuilder.appendNull();
            }
            else {
                Slice slice = source.slice(begend - beg);
                .writeSlice(blockBuilderslice);
            }
        }
        return buildStructuralSlice(blockBuilder);
    }
    @Nullable
    @Description("string extracted using the given pattern")
    public static Slice regexpExtract(@SqlType(.Slice source, @SqlType(.Regex pattern)
    {
        return regexpExtract(sourcepattern, 0);
    }
    @Nullable
    @Description("returns regex group of extracted string with a pattern")
    public static Slice regexpExtract(@SqlType(.Slice source, @SqlType(.Regex pattern, @SqlType(.long groupIndex)
    {
        Matcher matcher = pattern.matcher(source.getBytes());
        validateGroup(groupIndexmatcher.getEagerRegion());
        int group = Ints.checkedCast(groupIndex);
        int offset = matcher.search(0, source.length(), .);
        if (offset == -1) {
            return null;
        }
        Region region = matcher.getEagerRegion();
        int beg = region.beg[group];
        int end = region.end[group];
        if (beg == -1) {
            // end == -1 must be true
            return null;
        }
        Slice slice = source.slice(begend - beg);
        return slice;
    }
    @Description("returns array of strings split by pattern")
    @SqlType("array<varchar>")
    public static Slice regexpSplit(@SqlType(.Slice source, @SqlType(.Regex pattern)
    {
        Matcher matcher = pattern.matcher(source.getBytes());
        BlockBuilder blockBuilder = .createBlockBuilder(new BlockBuilderStatus(), 32);
        int lastEnd = 0;
        int nextStart = 0;
        while (true) {
            int offset = matcher.search(nextStartsource.length(), .);
            if (offset == -1) {
                break;
            }
            if (matcher.getEnd() == matcher.getBegin()) {
                nextStart = matcher.getEnd() + 1;
            }
            else {
                nextStart = matcher.getEnd();
            }
            Slice slice = source.slice(lastEndmatcher.getBegin() - lastEnd);
            lastEnd = matcher.getEnd();
            .writeSlice(blockBuilderslice);
        }
        .writeSlice(blockBuildersource.slice(lastEndsource.length() - lastEnd));
        return buildStructuralSlice(blockBuilder);
    }
    private static void validateGroup(long groupRegion region)
    {
        if (group < 0) {
            throw new PrestoException("Group cannot be negative");
        }
        if (group > region.numRegs - 1) {
            throw new PrestoException(format("Pattern has %d groups. Cannot access group %d"region.numRegs - 1, group));
        }
    }
New to GrepCode? Check out our FAQ X