package edu.stanford.nlp.patterns.surface;
import java.io.File;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import edu.stanford.nlp.io.IOUtils;
import edu.stanford.nlp.patterns.ConstantsAndVariables;
import edu.stanford.nlp.patterns.PatternFactory;
/** Currently can handle only ORs.
*
* @author sonalg
* @version 10/16/14
*/
public class Token implements Serializable {
//Can be semgrex.Env but does not matter
//static public Env env = TokenSequencePattern.getNewEnv();
static Map<Class, String> class2KeyMapping = new ConcurrentHashMap<>();
//All the restrictions of a token: for example, word:xyz
Map<Class, String> classORrestrictions;
//TODO: may be change this to map to true values?
String envBindBooleanRestriction;
private final Pattern alphaNumeric = Pattern.compile("^[\\p{Alnum}\\s]+$");
int numMinOcc = 1;
int numMaxOcc = 1;
PatternFactory.PatternType type;
public Token(PatternFactory.PatternType type){
this.type = type;
}
public Token(Class c, String s, PatternFactory.PatternType type){
this(type);
addORRestriction(c, s);
}
public Map<String, String> classORRestrictionsAsString(){
if(classORrestrictions== null || classORrestrictions.isEmpty())
return null;
Map<String, String> str = new HashMap<>();
for(Map.Entry<Class, String> en: classORrestrictions.entrySet()){
str.put(class2KeyMapping.get(en.getKey()), en.getValue());
}
return str;
}
@Override
public String toString() {
if (type.equals(PatternFactory.PatternType.SURFACE))
return toStringSurface();
else if (type.equals(PatternFactory.PatternType.DEP))
return toStringDep();
else
throw new UnsupportedOperationException();
}
private String toStringDep() {
String str = "";
if(classORrestrictions!= null && !this.classORrestrictions.isEmpty()) {
for (Map.Entry<Class, String> en : this.classORrestrictions.entrySet()) {
String orgVal = en.getValue().toString();
String val;
if(!alphaNumeric.matcher(orgVal).matches())
val = "/" + Pattern.quote(orgVal.replaceAll("/","\\\\/"))+ "/";
else
val = orgVal;
if (str.isEmpty())
str = "{" + class2KeyMapping.get(en.getKey()) + ":" + val + "}";
else
str += " | " + "{" + class2KeyMapping.get(en.getKey()) + ":" + val + "}";
}
}
return str.trim();
}
private String toStringSurface(){
String str = "";
if(classORrestrictions!= null && !this.classORrestrictions.isEmpty()) {
for (Map.Entry<Class, String> en : this.classORrestrictions.entrySet()) {
String orgVal = en.getValue().toString();
String val;
if(!alphaNumeric.matcher(orgVal).matches())
val = "/" + Pattern.quote(orgVal.replaceAll("/","\\\\/"))+ "/";
else
val = "\"" + orgVal +"\"";
if (str.isEmpty())
str = "{" + class2KeyMapping.get(en.getKey()) + ":" + val + "}";
else
str += " | " + "{" + class2KeyMapping.get(en.getKey()) + ":" + val + "}";
}
str = "[" + str + "]";
}else if(envBindBooleanRestriction != null && !envBindBooleanRestriction.isEmpty())
str = envBindBooleanRestriction;
if(numMinOcc != 1 || numMaxOcc != 1)
str+="{"+numMinOcc+","+numMaxOcc+"}";
return str.trim();
}
public String getSimple() {
String str = "";
if(classORrestrictions!= null && !this.classORrestrictions.isEmpty()) {
for (Map.Entry<Class, String> en : this.classORrestrictions.entrySet()) {
if (str.isEmpty())
str = en.getValue().toString();
else
str += "|" + en.getValue().toString();
}
}else if(envBindBooleanRestriction != null && !envBindBooleanRestriction.isEmpty()){
if(envBindBooleanRestriction.startsWith("$FILLER"))
str = "FW";
else if (envBindBooleanRestriction.startsWith("$STOP"))
str = "SW";
}
return str.trim();
}
@Override
public int hashCode(){
return toString().hashCode();
}
@Override
public boolean equals(Object o){
if(! (o instanceof Token))
return false;
return o.toString().equals(this.toString());
}
public void addORRestriction(Class classR, String value) {
getKeyForClass(classR);
if(this.envBindBooleanRestriction != null && !this.envBindBooleanRestriction.isEmpty())
throw new RuntimeException("cannot add restriction to something that is binding to an env variable");
if(classORrestrictions == null)
classORrestrictions = new TreeMap<>(new ClassComparator());
assert value!=null;
classORrestrictions.put(classR, value);
}
public void setEnvBindRestriction(String envBind) {
if(this.classORrestrictions != null && !this.classORrestrictions.isEmpty())
throw new RuntimeException("cannot add env bind restriction to something that has restricted");
this.envBindBooleanRestriction = envBind;
}
public void setNumOcc(int min, int max) {
numMinOcc = min;
numMaxOcc = max;
}
public boolean isEmpty() {
return (this.envBindBooleanRestriction == null || this.envBindBooleanRestriction.isEmpty()) && (this.classORrestrictions == null || this.classORrestrictions.isEmpty());
}
public static String getKeyForClass(Class classR) {
String key =class2KeyMapping.get(classR);
if(key == null){
for(Map.Entry<String, Object> vars: ConstantsAndVariables.globalEnv.getVariables().entrySet()){
if(vars.getValue().equals(classR)){
key = vars.getKey().toLowerCase();
class2KeyMapping.put(classR, key);
break;
}
}
}
if(key == null){
key = classR.getSimpleName().toLowerCase();
class2KeyMapping.put(classR, key);
ConstantsAndVariables.globalEnv.bind(key, classR);
}
return key;
}
public class ClassComparator implements Serializable, Comparator<Class>{
@Override
public int compare(Class o1, Class o2) {
return o1.toString().compareTo(o2.toString());
}
}
public static String toStringClass2KeyMapping(){
StringBuilder str = new StringBuilder();
for(Map.Entry<Class, String> en: class2KeyMapping.entrySet()){
if(str.length() > 0)
str.append("\n");
str.append(en.getKey().getName()+"###"+en.getValue());
}
return str.toString();
}
public static void setClass2KeyMapping(File file) throws ClassNotFoundException {
for(String line: IOUtils.readLines(file)){
String[] toks = line.split("###");
class2KeyMapping.put(Class.forName(toks[0]), toks[1]);
}
}
}