package org.nutz.lang.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
/**
* 解析命令参数
*
* @author zozoh(zozohtnt@gmail.com)
* @author wendal(wendal1985@gmail.com)
*/
public class CmdParams {
private static final Pattern PARAM_KEY = Pattern.compile("^-([a-zA-Z_].*)$");
public String[] vals;
NutMap map;
/**
* @see #parse(String[], String, String)
*/
public static CmdParams parse(String[] args, String bools) {
if (null == bools)
return parse(args, null, null);
if (bools.startsWith("^"))
return parse(args, null, bools);
return parse(args, bools, null);
}
/**
* 解析传入的参数表
*
* <pre>
* 如果参数以 "-" 开头,则所谓名值对的键。
* 如果后面接着一个 "-" 开头的参数,则认为当前项目是布尔
* 当然,如果给入的参数 boolChars 或者 boolRegex 匹配上了这个参数,也认为是布尔
* </pre>
*
* @param args
* 参数表
*
* @param boolChars
* 指明一个键的哪个字符是布尔值。 一个键如果全部内容都是布尔值,则分别记录。否则认为是一个普通键 <br>
* 你可以直接给一个正则表达式来匹配 boolChar,但是你的正则表达式必须得有 group(1) 表示内容
*
* @param boolRegex
* 用一个正则表达式来描述哪些键(参数的整体)为布尔值
*
* @return 参数表
*/
public static CmdParams parse(String[] args, String boolChars, String boolRegex) {
CmdParams params = new CmdParams();
List<String> list = new ArrayList<String>(args.length);
params.map = new NutMap();
if (args.length > 0) {
// 预编译 boolRegex
Pattern bool_key = null;
if (!Strings.isBlank(boolRegex)) {
bool_key = Pattern.compile(boolRegex);
}
// 预编译 boolChars,如果匹配这个正则表达式的参数,将被认为是一个布尔参数
// 支持 -bish 这样的组合形式
Pattern bool_char = null;
if (!Strings.isBlank(boolChars)) {
bool_char = Pattern.compile("^-([" + boolChars + "]+)$");
}
// 参数表 ...
int i = 0;
Matcher m;
for (; i < args.length; i++) {
String s = args[i];
// boolChars
// 是否是布尔值表
if (null != bool_char) {
m = bool_char.matcher(s);
if (m.find()) {
char[] cs = m.group(m.groupCount()).toCharArray();
for (char c : cs) {
params.map.put("" + c, true);
}
continue;
}
}
// 键值
m = PARAM_KEY.matcher(s);
if (m.find()) {
String key = m.group(m.groupCount());
// 键就是布尔值
if (null != bool_key && bool_key.matcher(key).matches()) {
params.map.put(key, true);
}
// 木有后面的值了,那么作为 boolean
else if (i >= args.length - 1) {
params.map.put(key, true);
break;
}
// 如果有值 ...
else {
s = args[i + 1];
if (s.matches("^-[a-zA-Z_].*$")) {
params.map.put(key, true);
continue;
}
params.map.put(key, s);
// 跳过下一个值
i++;
}
}
// 嗯,是普通值 ...
else {
list.add(s);
}
}
}
params.vals = list.toArray(new String[list.size()]);
return params;
}
protected CmdParams() {}
public String val(int index) {
int i = index >= 0 ? index : vals.length + index;
if (i < 0 || i >= vals.length)
return null;
return this.vals[i];
}
public String val_check(int index) {
String v = val(index);
if (null == v) {
throw Er.create("e.cmd.lack.param.vals", index);
}
return v;
}
public boolean is(String key) {
return map.getBoolean(key, false);
}
public boolean is(String key, boolean dft) {
return map.getBoolean(key, dft);
}
public void setv(String key, Object val) {
map.setv(key, val);
}
public boolean has(String key) {
return map.has(key);
}
public boolean hasString(String key) {
String val = this.get(key);
return !Strings.isBlank(val) && !"true".equals(val);
}
public float getFloat(String key) {
return map.getFloat(key, Float.NaN);
}
public float getFloat(String key, float dft) {
return map.getFloat(key, dft);
}
public int getInt(String key) {
return map.getInt(key, -1);
}
public int getInt(String key, int dft) {
return map.getInt(key, dft);
}
public long getLong(String key) {
return map.getLong(key, -1);
}
public long getLong(String key, long dft) {
return map.getLong(key, dft);
}
public double getDouble(String key) {
return map.getDouble(key, Double.NaN);
}
public double getDouble(String key, double dft) {
return map.getDouble(key, dft);
}
public String get(String key) {
return map.getString(key);
}
public String get(String key, String dft) {
return map.getString(key, dft);
}
public String getString(String key) {
return this.getString(key, "");
}
public String getString(String key, String dft) {
Object val = map.get(key);
if (null == val || val instanceof Boolean)
return dft;
return val.toString();
}
public String wrap(String key, String fmt) {
return wrap(key, fmt, "");
}
public String wrap(String key, String fmt, String dft) {
String val = this.get(key);
if (Strings.isBlank(val)) {
return dft;
}
return String.format(fmt, val);
}
public <T extends Enum<T>> T getEnum(String key, Class<T> classOfEnum) {
return map.getEnum(key, classOfEnum);
}
public <T> T getAs(String key, Class<T> classOfT) {
return map.getAs(key, classOfT);
}
public <T> T getAs(String key, Class<T> classOfT, T dft) {
return map.getAs(key, classOfT, dft);
}
public NutMap getMap(String key) {
return getMap(key, null);
}
@SuppressWarnings({"unchecked", "rawtypes"})
public NutMap getMap(String key, NutMap dft) {
Object val = map.get(key);
if (null == val)
return null;
if (val instanceof Map)
return NutMap.WRAP((Map) val);
return Lang.map(val.toString());
}
public <T> List<T> getList(String key, Class<T> eleType) {
return map.getList(key, eleType);
}
public String check(String key) {
String v = get(key);
if (Strings.isBlank(v)) {
throw Er.create("e.cmd.lack.param", key);
}
return v;
}
public int checkInt(String key) {
String v = get(key);
if (Strings.isBlank(v)) {
throw Er.create("e.cmd.lack.param.int", key);
}
return Integer.valueOf(v);
}
public long checkLong(String key) {
String v = get(key);
if (Strings.isBlank(v)) {
throw Er.create("e.cmd.lack.param.long", key);
}
return Long.valueOf(v);
}
public float checkFloat(String key) {
String v = get(key);
if (Strings.isBlank(v)) {
throw Er.create("e.cmd.lack.param.float", key);
}
return Float.valueOf(v);
}
public double checkDouble(String key) {
String v = get(key);
if (Strings.isBlank(v)) {
throw Er.create("e.cmd.lack.param.double", key);
}
return Double.valueOf(key);
}
public NutMap map() {
return map;
}
static class Er {
public static RuntimeException create(String msg, Object key) {
return new RuntimeException(String.format("%s : key=%s", msg, key));
}
}
}