Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: CPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Common Public License Version 1.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.eclipse.org/legal/cpl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2001 Alan Moore <alan_moore@gmx.net> Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de> Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr> Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se> Copyright (C) 2004 Thomas E Enebo <enebo@acm.org> Copyright (C) 2004 Charles O Nutter <headius@headius.com> Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the CPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the CPL, the GPL or the LGPL. END LICENSE BLOCK ***
 
 package org.jruby;
 
 
 import org.joni.Regex;
 import static org.jruby.CompatVersion.*;

Author(s):
olabini
 
 @JRubyClass(name="MatchData")
 public class RubyMatchData extends RubyObject {
     Region regs;        // captures
     int beginend;     // begin and end are used when not groups defined
     RubyString str;     // source string
     Regex pattern;
     RubyRegexp regexp;
     boolean charOffsetUpdated;
     Region charOffsets;
 
     public static RubyClass createMatchDataClass(Ruby runtime) {
         RubyClass matchDataClass = runtime.defineClass("MatchData"runtime.getObject(), );
         runtime.setMatchData(matchDataClass);
 
         matchDataClass.index = .;
         matchDataClass.setReifiedClass(RubyMatchData.class);
         
         runtime.defineGlobalConstant("MatchingData"matchDataClass);
         matchDataClass.kindOf = new RubyModule.KindOf() {
             @Override
             public boolean isKindOf(IRubyObject objRubyModule type) {
                 return obj instanceof RubyMatchData;
             }
         };
 
         matchDataClass.getMetaClass().undefineMethod("new");
         matchDataClass.defineAnnotatedMethods(RubyMatchData.class);
         return matchDataClass;
     }
 
     private static ObjectAllocator MATCH_DATA_ALLOCATOR = new ObjectAllocator() {
         public IRubyObject allocate(Ruby runtimeRubyClass klass) {
             return new RubyMatchData(runtimeklass);
         }
     };
 
     public RubyMatchData(Ruby runtime) {
         super(runtimeruntime.getMatchData());
     }
 
     public RubyMatchData(Ruby runtimeRubyClass metaClass) {
        super(runtimemetaClass);
    }
    @Override
    public void copySpecialInstanceVariables(IRubyObject clone) {
        RubyMatchData match = (RubyMatchData)clone;
        match.regs = ;
        match.begin = ;
        match.end = ;
        match.pattern = ;
        match.regexp = ;
        match.charOffsetUpdated = ;
        match.charOffsets = ;
    }
    @Override
    public int getNativeTypeIndex() {
        return .;
    }
    private static final class Pair implements Comparable<Pair> {
        int bytePoscharPos;
        public int compareTo(Pair pair) {
            return  - pair.bytePos;
        }
    }
    private void updatePairs(ByteList valueEncoding encodingPair[] pairs) {
        Arrays.sort(pairs);
        int length = pairs.length;
        byte[]bytes = value.getUnsafeBytes();
        int p = value.getBegin();
        int s = p;
        int c = 0;
        
        for (int i = 0; i < lengthi++) {
            int q = s + pairs[i].;
            c += StringSupport.strLength(encodingbytespq);
            pairs[i]. = c;
            p = q;
        }
    }
    private void updateCharOffsetOnlyOneReg(ByteList valueEncoding encoding) {
        if ( == null || . < 1)  = new Region(1);
        
        if (encoding.maxLength() == 1) {
            .[0] = ;
            .[0] = ;
             = true;
            return;
        }
        Pair[] pairs = new Pair[2];
        pairs[0] = new Pair();
        pairs[0]. = ;
        pairs[1] = new Pair();
        pairs[1]. = ;
        updatePairs(valueencodingpairs);
        Pair key = new Pair();
        key.bytePos = ;
        .[0] = pairs[Arrays.binarySearch(pairskey)].;
        key.bytePos = ;
        .[0] = pairs[Arrays.binarySearch(pairskey)].;        
    }
    private void updateCharOffsetManyRegs(ByteList valueEncoding encoding) {
        int numRegs = .;
        if ( == null || . < numRegs = new Region(numRegs);
        
        if (encoding.maxLength() == 1) {
            for (int i = 0; i < numRegsi++) {
                .[i] = .[i];
                .[i] = .[i];
            }
            return;
        }
        Pair[] pairs = new Pair[numRegs * 2];
        for (int i = 0; i < pairs.lengthi++) pairs[i] = new Pair();
        int numPos = 0;
        for (int i = 0; i < numRegsi++) {
            if (.[i] < 0) continue;
            pairs[numPos++]. = .[i];
            pairs[numPos++]. = .[i];
        }
        updatePairs(valueencodingpairs);
        Pair key = new Pair();
        for (int i = 0; i < .i++) {
            if (.[i] < 0) {
                .[i] = .[i] = -1;
                continue;
            }
            key.bytePos = .[i];
            .[i] = pairs[Arrays.binarySearch(pairskey)].;
            key.bytePos = .[i];
            .[i] = pairs[Arrays.binarySearch(pairskey)].;
        }        
    }
    private void updateCharOffset() {
        if (return;
        ByteList value = .getByteList();
        Encoding enc = value.getEncoding();
        if ( == null) {
            updateCharOffsetOnlyOneReg(valueenc);
        } else {
            updateCharOffsetManyRegs(valueenc);
        }
         = true;
    }
    private static final int MATCH_BUSY = ;
    // rb_match_busy
    public final void use() {
         |= 
    }
    public final boolean used() {
        return ( & ) != 0;
    }
    void check() {
        if ( == nullthrow getRuntime().newTypeError("uninitialized Match");
    }
    private void checkLazyRegexp() {
        if ( == null = RubyRegexp.newRegexp(getRuntime(), (ByteList).getUserObject(), );
    }
    
    // FIXME: We should have a better way of using the proper method based
    // on version as a general solution...
    private RubyString makeShared(Ruby runtimeRubyString strint beginint length) {
        if (runtime.is1_9()) {
            return str.makeShared19(runtimebeginlength);
        } else {
            return str.makeShared(runtimebeginlength);
        }
    }
    private RubyArray match_array(Ruby runtimeint start) {
        check();
        if ( == null) {
            if (start != 0) return runtime.newEmptyArray();
            if ( == -1) {
                return runtime.newArray(runtime.getNil());
            } else {
                RubyString ss = makeShared(runtime - );
                if (isTaint()) ss.setTaint(true);
                return runtime.newArray(ss);
            }
        } else {
            RubyArray arr = runtime.newArray(. - start);
            for (int i=starti<.i++) {
                if (.[i] == -1) {
                    arr.append(runtime.getNil());
                } else {
                    RubyString ss = makeShared(runtime.[i], .[i] - .[i]);                   
                    if (isTaint()) ss.setTaint(true); 
                    arr.append(ss);
                }
            }
            return arr;
        }
        
    }
    public IRubyObject group(long n) {
        return RubyRegexp.nth_match((int)nthis);
    }
    public IRubyObject group(int n) {
        return RubyRegexp.nth_match(nthis);
    }
    // This returns a list of values in the order the names are defined (named capture local var
    // feature uses this).
    public IRubyObject[] getNamedBackrefValues(Ruby runtime) {
        if (.numberOfNames() == 0) return ;
        IRubyObject[] values = new IRubyObject[.numberOfNames()];
        int j = 0;
        for (Iterator<NameEntryi = .namedBackrefIterator(); i.hasNext();) {
            NameEntry e = i.next();
            int[] refs = e.getBackRefs();
            int length = refs.length;
            values[j++] = length == 0 ? runtime.getNil() : RubyRegexp.nth_match(refs[length - 1], this);
        }
        return values;
    }
    @JRubyMethod(name = "inspect")
    @Override
    public IRubyObject inspect() {
        if ( == nullreturn anyToString();
        Ruby runtime = getRuntime();
        RubyString result = runtime.newString();
        result.cat((byte)'#').cat((byte)'<');
        result.append(getMetaClass().getRealClass().to_s());
        NameEntry[]names = new NameEntry[ == null ? 1 : .];
        if (.numberOfNames() > 0) {
            for (Iterator<NameEntryi = .namedBackrefIterator(); i.hasNext();) {
                NameEntry e = i.next();
                for (int num : e.getBackRefs()) names[num] = e;
            }
        }
        for (int i=0; i<names.lengthi++) {
            result.cat((byte)' ');
            if (i > 0) {
                NameEntry e = names[i];
                if (e != null) {
                    result.cat(e.namee.namePe.nameEnd - e.nameP);
                } else {
                    result.cat((byte)('0' + i));
                }
                result.cat((byte)':');
            }
            IRubyObject v = RubyRegexp.nth_match(ithis);
            if (v.isNil()) {
                result.cat("nil".getBytes());
            } else {
                result.append(runtime.is1_9() ? ((RubyString)v).inspect19() : ((RubyString)v).inspect());
            }
        }
        return result.cat((byte)'>');
    }
    @JRubyMethod(name = "regexp", compat = .)
    public IRubyObject regexp(ThreadContext contextBlock block) {
        check();
        checkLazyRegexp();
        return ;
    }
    @JRubyMethod(name = "names", compat = .)
    public IRubyObject names(ThreadContext contextBlock block) {
        check();
        checkLazyRegexp();
        return .names(context);
    }

    
match_to_a
    @JRubyMethod(name = "to_a")
    @Override
    public RubyArray to_a() {
        return match_array(getRuntime(), 0);
    }
    @JRubyMethod(name = "values_at", rest = true)
    public IRubyObject values_at(IRubyObject[] args) {
        return to_a().values_at(args);
    }
    @JRubyMethod(compat = .)
    public IRubyObject select(ThreadContext contextBlock block) {
        Ruby runtime = context.runtime;
        final RubyArray result;
        if ( == null) {
            if ( < 0) return runtime.newEmptyArray();
            IRubyObject s = .substr(runtime - );
            s.setTaint(isTaint());
            result = block.yield(contexts).isTrue() ? runtime.newArray(s) : runtime.newEmptyArray();
        } else {
            result = runtime.newArray();
            boolean taint = isTaint();
            for (int i = 0; i < .i++) {
                IRubyObject s = .substr(runtime.[i], .[i] - .[i]);
                if (taints.setTaint(true);
                if (block.yield(contexts).isTrue()) result.append(s);
            }
        }
        return result;
    }

    
match_captures
    @JRubyMethod(name = "captures")
    public IRubyObject captures(ThreadContext context) {
        return match_array(context.runtime, 1);
    }
    private int nameToBackrefNumber(RubyString str) {
        ByteList value = str.getByteList();
        try {
            return .nameToBackrefNumber(value.getUnsafeBytes(), value.getBegin(), value.getBegin() + value.getRealSize(), );
        } catch (JOniException je) {
            throw getRuntime().newIndexError(je.getMessage());
        }
    }
    public final int backrefNumber(IRubyObject obj) {
        check();
        if (obj instanceof RubySymbol) {
            return nameToBackrefNumber((RubyString)((RubySymbol)obj).id2name());
        } else if (obj instanceof RubyString) {
            return nameToBackrefNumber((RubyString)obj);
        } else {
            return RubyNumeric.num2int(obj);
        }
    }

    
Variable arity version for compatibility. Not bound to a Ruby method.

Deprecated:
Use the versions with zero, one, or two args.
    public IRubyObject op_aref(IRubyObject[] args) {
        switch (args.length) {
        case 1:
            return op_aref(args[0]);
        case 2:
            return op_aref(args[0], args[1]);
        default:
            Arity.raiseArgumentError(getRuntime(), args.length, 1, 2);
            return null// not reached
        }
    }

    
match_aref
    @JRubyMethod(name = "[]")
    public IRubyObject op_aref(IRubyObject idx) {
        check();
        if (!(idx instanceof RubyFixnum) || ((RubyFixnum)idx).getLongValue() < 0) {
            return ((RubyArray)to_a()).aref(idx);
        }
        return RubyRegexp.nth_match(RubyNumeric.fix2int(idx), this);
    }

    
match_aref
    @JRubyMethod(name = "[]")
    public IRubyObject op_aref(IRubyObject idxIRubyObject rest) {
        if (!rest.isNil() || !(idx instanceof RubyFixnum) || ((RubyFixnum)idx).getLongValue() < 0) {
            return ((RubyArray)to_a()).aref(idxrest);
        }
        return RubyRegexp.nth_match(RubyNumeric.fix2int(idx), this);
    }

    
match_aref
    @JRubyMethod(name = "[]", compat = .)
    public IRubyObject op_aref19(IRubyObject idx) {
        check();
        IRubyObject result = op_arefCommon(idx);
        return result == null ? ((RubyArray)to_a()).aref19(idx) : result;
    }

    
match_aref
    @JRubyMethod(name = "[]", compat = .)
    public IRubyObject op_aref19(IRubyObject idxIRubyObject rest) {
        IRubyObject result;
        return !rest.isNil() || (result = op_arefCommon(idx)) == null ? ((RubyArray)to_a()).aref19(idxrest) : result;
    }
    private IRubyObject op_arefCommon(IRubyObject idx) {
        if (idx instanceof RubyFixnum) {
            int num = RubyNumeric.fix2int(idx);
            if (num >= 0) return RubyRegexp.nth_match(numthis);
        } else {
            if (idx instanceof RubySymbol) {
                return RubyRegexp.nth_match(nameToBackrefNumber((RubyString)((RubySymbol)idx).id2name()), this);
            } else if (idx instanceof RubyString) {
                return RubyRegexp.nth_match(nameToBackrefNumber((RubyString)idx), this);
            }
        }
        return null;
    }

    
match_size
    @JRubyMethod(name = {"size""length"})
    public IRubyObject size(ThreadContext context) {
        check();
        Ruby runtime = context.runtime;
        return  == null ? RubyFixnum.one(runtime) : RubyFixnum.newFixnum(runtime.);
    }

    
match_begin
    @JRubyMethod(name = "begin", compat = .)
    public IRubyObject begin(ThreadContext contextIRubyObject index) {
        int i = RubyNumeric.num2int(index);
        Ruby runtime = context.runtime;
        int b = beginCommon(runtimei);
        return b < 0 ? runtime.getNil() : RubyFixnum.newFixnum(runtimeb);
    }
    @JRubyMethod(name = "begin", compat = .)
    public IRubyObject begin19(ThreadContext contextIRubyObject index) {
        int i = backrefNumber(index);
        Ruby runtime = context.runtime;
        int b = beginCommon(runtimei);
        if (b < 0) return runtime.getNil();
        if (!.singleByteOptimizable()) {
            updateCharOffset();
            b = .[i];
        }
        return RubyFixnum.newFixnum(runtimeb);
    }
    private int beginCommon(Ruby runtimeint i) {
        check();
        if (i < 0 || ( == null ? 1 : .) <= ithrow runtime.newIndexError("index " + i + " out of matches");
        return  == null ?  : .[i];
    }

    
match_end
    @JRubyMethod(name = "end", compat = .)
    public IRubyObject end(ThreadContext contextIRubyObject index) {
        int i = RubyNumeric.num2int(index);
        Ruby runtime = context.runtime;
        int e = endCommon(runtimei);
        return e < 0 ? runtime.getNil() : RubyFixnum.newFixnum(runtimee);
    }
    @JRubyMethod(name = "end", compat = .)
    public IRubyObject end19(ThreadContext contextIRubyObject index) {
        int i = backrefNumber(index);
        Ruby runtime = context.runtime;
        int e = endCommon(runtimei);
        if (e < 0) return runtime.getNil();
        if (!.singleByteOptimizable()) {
            updateCharOffset();
            e = .[i];
        }
        return RubyFixnum.newFixnum(runtimee);
    }
    private int endCommon(Ruby runtimeint i) {
        check();
        if (i < 0 || ( == null ? 1 : .) <= ithrow runtime.newIndexError("index " + i + " out of matches");
        return  == null ?  : .[i];
    }

    
match_offset
    @JRubyMethod(name = "offset", compat = .)
    public IRubyObject offset(ThreadContext contextIRubyObject index) {
        return offsetCommon(context, RubyNumeric.num2int(index), false);
    }
    @JRubyMethod(name = "offset", compat = .)
    public IRubyObject offset19(ThreadContext contextIRubyObject index) {
        return offsetCommon(contextbackrefNumber(index), true);
    }
    private IRubyObject offsetCommon(ThreadContext contextint iboolean is_19) {
        check();
        Ruby runtime = context.runtime;
        if (i < 0 || ( == null ? 1 : .) <= ithrow runtime.newIndexError("index " + i + " out of matches");
        int be;
        if ( == null) {
            b = ;
            e = ;
        } else {
            b = .[i];
            e = .[i];
        }
        if (b < 0) return runtime.newArray(runtime.getNil(), runtime.getNil());
        if (is_19 && !.singleByteOptimizable()) {
            updateCharOffset();
            b = .[i];
            e = .[i];
        }
        return runtime.newArray(RubyFixnum.newFixnum(runtimeb), RubyFixnum.newFixnum(runtimee));
    }

    
match_pre_match
    @JRubyMethod(name = "pre_match")
    public IRubyObject pre_match(ThreadContext context) {
        check();
        if ( == -1) {
            return context.runtime.getNil();
        }
        return makeShared(context.runtime, 0, ).infectBy(this);
    }

    
match_post_match
    @JRubyMethod(name = "post_match")
    public IRubyObject post_match(ThreadContext context) {
        check();
        if ( == -1) {
            return context.runtime.getNil();
        }
        return makeShared(context.runtime.getByteList().length() - ).infectBy(this);
    }

    
match_to_s
    @JRubyMethod(name = "to_s")
    @Override
    public IRubyObject to_s() {
        check();
        IRubyObject ss = RubyRegexp.last_match(this);
        if (ss.isNil()) ss = RubyString.newEmptyString(getRuntime());
        if (isTaint()) ss.setTaint(true);
        return ss;
    }

    
match_string
    @JRubyMethod(name = "string")
    public IRubyObject string() {
        check();
        return //str is frozen
    }
    @JRubyMethod(name = "initialize_copy", required = 1)
    @Override
    public IRubyObject initialize_copy(IRubyObject original) {
        if (this == originalreturn this;
        Ruby runtime = getRuntime();
        ThreadContext context = runtime.getCurrentContext();
        if ((original instanceof RubyBasicObject) && !((RubyBasicObject)original).instance_of_p(contextgetMetaClass()).isTrue()) {
            throw runtime.newTypeError("wrong argument class");
        }
        RubyMatchData origMatchData = (RubyMatchData)original;
         = origMatchData.str;
         = origMatchData.regs;
        return this;
    }
    public boolean equals(Object other) {
        if (this == otherreturn true;
        if (!(other instanceof RubyMatchData)) return false;
        RubyMatchData match = (RubyMatchData)other;
        return (this. == match.str || (this. != null && this..equals(match.str))) &&
                (this. == match.regexp || (this. != null && this..equals(match.regexp))) &&
                (this. == match.charOffsets || (this. != null && this..equals(match.charOffsets))) &&
                this. == match.begin &&
                this. == match.end &&
                this. == match.charOffsetUpdated;
    }
    @JRubyMethod(name = {"eql?""=="}, required = 1, compat = )
    @Override
    public IRubyObject eql_p(IRubyObject obj) {
        return getRuntime().newBoolean(equals(obj));
    }
    @JRubyMethod(name = "hash", compat = )
    @Override
    public RubyFixnum hash() {
        check();
        return getRuntime().newFixnum(.hashCode() ^ .hashCode());
    }