package com.jmatio.common.util; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.jmatio.types.MLArray; import com.jmatio.types.MLCell; import com.jmatio.types.MLChar; import com.jmatio.types.MLNumericArray; import com.jmatio.types.MLObject; import com.jmatio.types.MLStructure; /** * The JMatIO query parser. Allows to use Matlab-like syntax to access {@link MLArray} objects. *

* * @author wgradkowski * */ public class MLArrayQuery { private String queryString; private static final String regexp = "([a-zA-Z0-9]+)(\\(([0-9]+|:)(,([0-9:]+|:))?\\))?\\.?"; private static final Pattern pat = Pattern.compile( regexp ); public MLArrayQuery( String queryString ) { if ( !Pattern.matches( "^(" + regexp + ")+$", queryString ) ) { throw new IllegalArgumentException(); } this.queryString = queryString; } /** * * * @param array * @param query * @return */ public static Object q( MLArray array, String query ) { MLArrayQuery q = new MLArrayQuery( query ); return q.query( array ); } /** * Parses the query string and returns the object it refers to. * * @param array * source {@link MLArray} * @return query result */ public Object query( MLArray array ) { Matcher mat = pat.matcher( queryString ); MLArray current = null; int prevM = 0; int prevN = 0; while ( mat.find() ) { String name = mat.group( 1 ); String rangeM = mat.group( 3 ); String rangeN = mat.group( 5 ); int m = rangeM != null ? Integer.parseInt( rangeM ) -1 : -1; int n = rangeN != null ? Integer.parseInt( rangeN ) -1 : -1; if ( current == null ) { current = array; if ( !current.getName().equals( name ) && !current.getName().equals( "@" ) ) { throw new RuntimeException("No such array or field <" + name + "> in <" + (current != null ? current.getName() : "/") + ">" ); } prevM = m; prevN = n; continue; } int type = current.getType(); switch ( type ) { case MLArray.mxOBJECT_CLASS: { MLObject object = (MLObject) current; MLArray field = object.getObject().getField( name, prevM, prevN ); if ( field == null ) { throw new RuntimeException("no such field: " + name ); } current = field; } break; case MLArray.mxSTRUCT_CLASS: { MLStructure struct = (MLStructure) current; MLArray field = struct.getField( name, prevM > 0 ? prevM : 0, prevN > 0 ? prevN : 0 ); if ( field == null ) { throw new RuntimeException("no such field: " + name ); } current = field; } break; case MLArray.mxCELL_CLASS: { MLCell mlcell = (MLCell) current; if ( m > -1 && n > -1 ) { current = mlcell.get( m, n ); } else if ( m > -1 ) { current = mlcell.get( m ); } else { throw new RuntimeException(); } } break; default: } prevM = m; prevN = n; } return getContent(current, prevM, prevN ); } /** * Returns the content of the field/cell/object. * * @param array * the parent structure/cell * @param m * column or -1 * @param n * row or -1 * @return if both m and n are -1, returns {@link MLArray}, if n is -1, returns * content under index m, if both m and n are not-negative, returns * content of (m,n) */ public Object getContent( MLArray array, int m, int n ) { int type = array.getType(); Object result = null; switch ( type ) { case MLArray.mxINT8_CLASS: case MLArray.mxINT16_CLASS: case MLArray.mxINT32_CLASS: case MLArray.mxINT64_CLASS: case MLArray.mxUINT8_CLASS: case MLArray.mxUINT16_CLASS: case MLArray.mxUINT32_CLASS: case MLArray.mxUINT64_CLASS: case MLArray.mxSINGLE_CLASS: case MLArray.mxDOUBLE_CLASS: MLNumericArray numeric = (MLNumericArray) array; if ( m > -1 && n > -1 ) { result = numeric.get( m, n ); } else if ( m > -1 ) { result = numeric.get( m ); } else { result = array; } break; case MLArray.mxCHAR_CLASS: MLChar mlchar = (MLChar) array; if ( m > -1 && n > -1 ) { result = mlchar.getChar( m, n ); } else if ( m > -1 ) { result = mlchar.getString( m ); } else { result = mlchar; } break; case MLArray.mxCELL_CLASS: MLCell mlcell = (MLCell) array; if ( m > -1 && n > -1 ) { result = getContent( mlcell.get( m, n ), 0, -1); } else if ( m > -1 ) { result = getContent( mlcell.get( m ), 0, -1 ); } else { result = getContent( mlcell.get( 0 ), -1, -1 ); } break; default: result = array; } return result; } }