package org.nutz.lang.util; import org.nutz.castor.Castors; import org.nutz.lang.Mirror; import org.nutz.lang.Strings; /** * 描述了一个区间 * <ul> * <li>T 对象必须实现有意义的 toString,并且字符串中不能包含半角逗号 * <li>T 对象必须可比较 * <li>T 对象必须可以被 Castors 正确的从字符串转换 * <li>T 对象的 toString() 和 Castors 的转换必须可逆 * </ul> * * 任何区间的字符串描述都符合: * * <pre> * 全封闭的区间 : [T0, T1] * 左开右闭区间 : (T0, T1] * 左闭右开区间 : [T0, T1) * 左开右闭区间 : (T0, T1] * 全开放的区间 : (T0, T1) * 精确等于某值 : (T0) 或 [T0) # 总之开闭区间无所谓了 * </pre> * * 比如对于数字: * * <pre> * [4,10] // >=4 && <=10 * (6,54] // >=6 && <54 * (,78) // <78 * </pre> * * 对于日期 * * <pre> * [2012-09-10 12:33:24, 2013-08-14] // 会自动交换大小值,可以是日期或者时间 * </pre> * * @author zozoh(zozohtnt@gmail.com) */ public abstract class Region<T extends Comparable<T>> { public static IntRegion Int(String str) { return new IntRegion(str); } public static IntRegion Intf(String fmt, Object... args) { return new IntRegion(String.format(fmt, args)); } public static LongRegion Long(String str) { return new LongRegion(str); } public static LongRegion Longf(String fmt, Object... args) { return new LongRegion(String.format(fmt, args)); } public static FloatRegion Float(String str) { return new FloatRegion(str); } public static FloatRegion Floatf(String fmt, Object... args) { return new FloatRegion(String.format(fmt, args)); } public static DoubleRegion Double(String str) { return new DoubleRegion(str); } public static DoubleRegion Doublef(String fmt, Object... args) { return new DoubleRegion(String.format(fmt, args)); } public static DateRegion Date(String str) { return new DateRegion(str); } public static DateRegion Datef(String fmt, Object... args) { return new DateRegion(String.format(fmt, args)); } protected Class<T> eleType; protected T left; protected T right; protected boolean leftOpen; protected boolean rightOpen; public T left() { return left; } public Region<T> left(T left) { this.left = left; return this; } public Region<T> leftOpen(boolean open) { this.leftOpen = open; return this; } public T right() { return right; } public Region<T> right(T right) { this.right = right; return this; } public Region<T> rightOpen(boolean open) { this.rightOpen = open; return this; } public boolean isLeftOpen() { return leftOpen; } public boolean isRightOpen() { return rightOpen; } /** * @return 是区间还是一个精确匹配的值 */ public boolean isRegion() { return left != right && !isNull(); } /** * @return 当前区间是否为空 */ public boolean isNull() { return null == left && null == right; } /** * 根据左边开闭区间的情况返回一个正确的左边比较的运算符 * * @param gt * 大于的运算符,开区间时采用 * @param gte * 大于等于的运算符,闭区间时采用 * @return 运算符 */ public String leftOpt(String gt, String gte) { if (null == left) return null; return leftOpen ? gt : gte; } /** * 根据右边开闭区间的情况返回一个正确的右边比较的运算符 * * @param lt * 小于的运算符,开区间时采用 * @param lte * 小于等于的运算符,闭区间时采用 * @return 运算符 */ public String rightOpt(String lt, String lte) { if (null == right) return null; return rightOpen ? lt : lte; } /** * @param obj * 对象 * @return 对象是否在这个区间 */ public boolean match(T obj) { if (null == obj) return false; if (!isRegion()) { return left.compareTo(obj) == 0; } if (null != left) { int c = obj.compareTo(left); if (c < 0 || c == 0 && leftOpen) { return false; } } if (null != right) { int c = obj.compareTo(right); if (c > 0 || c == 0 && rightOpen) { return false; } } return true; } @SuppressWarnings({"unchecked", "rawtypes"}) public Region() { eleType = (Class<T>) (Class) Mirror.getTypeParam(getClass(), 0); } /** * 解析 * * @param str * 字符串 * @return 自身 */ public Region<T> valueOf(String str) { String s2 = Strings.trim(str.substring(1, str.length() - 1)); leftOpen = str.charAt(0) == '('; rightOpen = str.charAt(str.length() - 1) == ')'; // 只有左值 if (s2.endsWith(",")) { left = fromString(Strings.trim(s2.substring(0, s2.length() - 1))); right = null; } // 只有右值 else if (s2.startsWith(",")) { left = null; right = fromString(Strings.trim(s2.substring(1))); } // 两侧都有值 else { String[] ss = Strings.splitIgnoreBlank(s2, ","); // 精确的值 if (1 == ss.length) { left = fromString(ss[0]); right = left; } // 一个区间 else { left = fromString(ss[0]); right = fromString(ss[1]); // 看看是否需要交换交换... if (null != left && null != right && left.compareTo(right) > 0) { T o = right; right = left; left = o; } } } return this; } public String toString(T obj) { return null == obj ? "" : obj.toString(); } public T fromString(String str) { str = Strings.trim(str); if (Strings.isEmpty(str)) return null; return Castors.me().castTo(str, eleType); } public String toString() { if (this.isRegion()) return String.format("%c%s,%s%c", leftOpen ? '(' : '[', toString(left), toString(right), rightOpen ? ')' : ']'); return String.format("%c%s%c", leftOpen ? '(' : '[', toString(left), rightOpen ? ')' : ']'); } }