code: package caevo.util;
  
  import java.io.BufferedReader;
  import java.io.StringReader;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.Vector;
  
  import caevo.NERSpan;
  import caevo.SieveSentence;
  import caevo.TextEvent;
  import edu.stanford.nlp.ling.HasWord;
  import edu.stanford.nlp.ling.Word;
  import edu.stanford.nlp.parser.lexparser.LexicalizedParser;
  import edu.stanford.nlp.process.DocumentPreprocessor;
  import edu.stanford.nlp.process.PTBTokenizer;
  import edu.stanford.nlp.process.PTBTokenizer.PTBTokenizerFactory;
  import edu.stanford.nlp.process.Tokenizer;
  import edu.stanford.nlp.process.TokenizerFactory;
  import edu.stanford.nlp.trees.Tree;
  import edu.stanford.nlp.trees.TypedDependency;
  
  /**
   * Nate Chambers
   */
  public class Ling {
    public enum Tense {
      present, past, future
    };
  
    public static final String DEP_SUBJECT = "s";
    public static final String DEP_OBJECT = "o";
    public static final String DEP_PREP = "p";
  
    Ling() {
    }
  
    // public static Tense getTenseOfVerb(Tree tree, int index) {
    // Tree subtree = TreeOperator.indexToSubtree(tree, index);
    //
    // Tree parent = subtree.parent(tree);
    //
    // return Tense.present;
    // }
  
    public static LexicalizedParser createParser(String grammarPath) {
      return LexicalizedParser.loadModel(grammarPath);
    }
  
    /**
     * @return true if the given string is a wh-word
     */
    public static boolean isWhWord(String token) {
      if (token.equals("who") || token.equals("what") || token.equals("where")
          || token.equals("when") || token.equals("why") || token.equals("which")
          || token.equals("how"))
        return true;
      else
        return false;
    }
  
    /**
     * Returns true if the given string is a person reference
     */
    public static boolean isPersonRef(String token) {
      if (token.equals("man") || token.equals("woman") || token.equals("men")
          || token.equals("women") || token.equals("person")
          || token.equals("people") || token.equals("boy")
          || token.equals("girl"))
        return true;
      else
        return false;
    }
  
    public static boolean isAbstractPerson(String token) {
      if (token.equals("nobody") || token.equals("noone")
          || token.equals("someone") || token.equals("somebody")
          || token.equals("anyone") || token.equals("anybody"))
        return true;
      else
        return false;
    }
  
    /**
     * Returns true if the given string is a person pronoun
     */
    public static boolean isPersonPronoun(String token) {
      if (token.equals("he") || token.equals("him") || token.equals("his")
          || token.equals("himself") || token.equals("she") || token.equals("her")
          || token.equals("hers") || token.equals("herself")
          || token.equals("you") || token.equals("yours")
          || token.equals("yourself") || token.equals("we") || token.equals("us")
          || token.equals("our") || token.equals("ours")
          || token.equals("ourselves") || token.equals("i") || token.equals("me")
          || token.equals("my") || token.equals("mine") || token.equals("they")
          || token.equals("them") || token.equals("their")
          || token.equals("themselves"))
        return true;
      else
        return false;
    }
  
    /**
     * Returns true if the given string is a potential non-person pronoun
     */
    public static boolean isInanimatePronoun(String token) {
      if (token.equals("it") || token.equals("itself") || token.equals("its")
          || token.equals("they") || token.equals("them") || token.equals("their")
          || token.equals("one"))
        return true;
      else
        return false;
    }
  
    public static boolean isObjectReference(String token) {
      if (token.equals("that") || token.equals("this") || token.equals("those")
          || token.equals("these") || token.equals("the"))
        return true;
      else
        return false;
    }
  
    private static final Set<String> NUMERALS = new HashSet<String>() {
      {
        add("one");
        add("two");
        add("three");
        add("four");
        add("five");
        add("six");
        add("seven");
        add("eight");
        add("nine");
        add("ten");
      }
    };
  
    public static boolean isNumber(String token) {
      if (NUMERALS.contains(token) || token.matches("^[\\d\\s\\.-/\\\\]+$"))
        return true;
      return false;
    }
  
    /**
     * @return True if the token's first letter is capitalized: A-Z. False
     *         otherwise.
     */
    public static boolean isCapitalized(String token) {
      if (token != null && token.length() > 0) {
        char first = token.charAt(0);
        if (first >= 'A' && first <= 'Z')
          return true;
      }
      return false;
    }
  
    /**
     * Remove the determiner if there is one at the beginning of this string,
     * followed by a space. Trim the string including the space char.
     */
    public static String trimLeadingDeterminer(String str) {
      int space = str.indexOf(' ');
      if (space != -1) {
        char ch = str.charAt(0);
        if (ch == 't' || ch == 'T' || ch == 'A' || ch == 'a') {
          String lower = str.toLowerCase();
          if (lower.startsWith("the ") || lower.startsWith("a ")
              || lower.startsWith("an ") || lower.startsWith("these ")
              || lower.startsWith("those "))
            return str.substring(space + 1);
        }
      }
      return str;
    }
  
    public static Map<Integer, String> particlesInSentence(
        Collection<TypedDependency> deps) {
      // Find any particles - O(n)
      Map<Integer, String> particles = new HashMap<Integer, String>();
      for (TypedDependency dep : deps) {
        if (dep.reln().toString().equals("prt")) {
          particles.put(dep.gov().index(), dep.dep().label().value());
        }
      }
      return particles;
    }
  
    public static String normalizeRelation(String reln) {
      return normalizeRelation(reln, true);
    }
  
    /**
     * @param reln
     *          The full Stanford relation string.
     * @param fullprep
     *          True if you want 'p_during', False if you just want 'p'.
     * @return A (possibly) shortened version of the relation, merging several
     *         types into a smaller set of relations.
     */
    public static String normalizeRelation(String reln, boolean fullprep) {
      // assume one letter words are already reduced...
      if (reln.length() == 1)
        return reln;
  
      if (reln.contains("conj"))
        return "conj";
      // ccomp, acomp, xcomp
      else if (reln.contains("comp") && !reln.equals("complm"))
        return "comp";
      else if (reln.contains("mod") && !reln.equals("advmod")
          && !reln.equals("tmod") && !reln.equals("quantmod"))
        return "mod";
      // nsubj, xsubj, SUBJ
      else if (!reln.contains("pass") && // !nsubjpass
          (reln.contains("subj") || reln.startsWith("S") || reln.startsWith("s")))
        return DEP_SUBJECT;
      // agent
      else if (reln.equals("agent"))
        return DEP_SUBJECT;
      // prep_X, PPOBJ
      else if (reln.startsWith("prep") || reln.startsWith("pp")
          || reln.equals("PPOBJ")) {
        int underscore = reln.indexOf('_');
        if (!fullprep || underscore == -1)
          return DEP_PREP;
        else
          return DEP_PREP + "_" + reln.substring(underscore + 1);
      }
      // dobj, iobj
      else if (reln.endsWith("obj") || reln.equals("nsubjpass"))
        return DEP_OBJECT;
      // others
      else
        return reln;
    }
  
    /**
     * Build a single string of the given List with spaces between the tokens.
     * 
     * @param words
     *          Any List of HasWord objects.
     * @return A single string (the sentence).
     */
    public static String appendTokens(List<HasWord> words) {
      if (words == null)
        return null;
  
      int i = 0;
      StringBuffer buf = new StringBuffer();
      for (HasWord word : words) {
        if (i > 0)
          buf.append(' ');
        buf.append(word.word());
        i++;
      }
      return buf.toString();
    }
  
    public static List<List<HasWord>> getSentencesFromText(String str,
        boolean invertible, String options) {
      List<List<HasWord>> sentences = new ArrayList<List<HasWord>>();
      StringReader reader = new StringReader(str);
      DocumentPreprocessor dp = new DocumentPreprocessor(reader);
      TokenizerFactory<? extends HasWord> factory = null;
  
      if (invertible) {
        factory = PTBTokenizer.factory(true, true);
        if (options != null && options.length() > 0)
          options = "invertible=true, " + options;
        else
          options = "invertible=true";
      } else
        factory = PTBTokenizer.factory();
  
      // System.out.println("Setting splitter options=" + options);
      factory.setOptions(options);
      dp.setTokenizerFactory(factory);
  
      Iterator<List<HasWord>> iter = dp.iterator();
      while (iter.hasNext()) {
        List<HasWord> sentence = iter.next();
        sentences.add(sentence);
      }
      return sentences;
  
    }
  
    /**
     * Splits a string that might contain multiple sentences into lists of
     * sentences.
     */
    public static List<List<HasWord>> getSentencesFromTextNoNorm(String str) {
      return getSentencesFromText(str, false, "ptb3Escaping=false");
    }
  
    /**
     * Splits a string that might contain multiple sentences into lists of
     * sentences. This function does not change any characters (e.g., " -> ''),
     * and preserves whitespace in the word objects.
     */
    public static List<List<HasWord>> getSentencesFromTextNormInvertible(
        String str) {
      return getSentencesFromText(str, true, "");
    }
  
    /**
     * Splits a string that might contain multiple sentences into lists of
     * sentences. This function does not change any characters (e.g., " -> ''),
     * and preserves whitespace in the word objects.
     */
    public static List<List<HasWord>> getSentencesFromTextNoNormInvertible(
        String str) {
      return getSentencesFromText(str, true, "ptb3Escaping=false");
    }
  
    /**
     * Splits a string that might contain multiple sentences into lists of
     * sentences.
     */
    public static List<List<HasWord>> getSentencesFromText(String str) {
      return getSentencesFromText(str, false, "americanize=false");
    }
  
    // NATE note: never actually double-checked that this new function works...
    public static List<Word> getWordsFromString(String str) {
      PTBTokenizerFactory<Word> factory = (PTBTokenizerFactory<Word>) PTBTokenizer
          .factory();
      // Stanford's tokenizer actually changes words to American...altering our
      // original text. Stop it!!
      factory.setOptions("americanize=false");
      Tokenizer<Word> tokenizer = factory
          .getTokenizer(new BufferedReader(new StringReader(str)));
      return tokenizer.tokenize();
    }
  
    // DocumentPreprocessor dp = new DocumentPreprocessor(new StringReader(str));
    // List<Word> words = dp.getWordsFromString(str);
    // }
  
    /**
     * Removes all leading and trailing punctuation.
     */
    public static String trimPunctuation(String token) {
      int start = 0, end = 0;
      for (start = 0; start < token.length(); start++) {
        char ch = token.charAt(start);
        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
            || (ch >= '0' && ch <= '9'))
          break;
      }
  
      if (start < token.length())
        for (end = token.length() - 1; end >= 0; end--) {
          char ch = token.charAt(end);
          if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
              || (ch >= '0' && ch <= '9'))
            break;
        }
  
      if (start > end)
        return "";
      else if (start > 0 || end < token.length() - 1)
        return token.substring(start, end + 1);
      else
        return token;
    }
  
    /**
     * @return True if the indexed word has a known definite determiner. False
     *         otherwise, but this doesn't necessarily mean it's not definite.
     */
    public static boolean isDefinite(Collection<TypedDependency> deps,
        int index) {
      String det = getDeterminer(deps, index);
      if (det.startsWith("th"))
        return true;
      else
        return false;
    }
  
    /**
     * Given a token index, return the determiner (e.g., "the") for the token, if
     * one exists.
     * 
     * @param deps
     *          All dependencies in the sentence.
     * @param index
     *          The index of the token
     * @return The String determiner, or null if none
     */
    public static String getDeterminer(Collection<TypedDependency> deps,
        int index) {
      for (TypedDependency dep : deps) {
        if (dep.gov().index() == index)
          if (dep.reln().toString().equals("det"))
            return dep.dep().value();
      }
      return null;
    }
  
    public static boolean isProper(List<NERSpan> ners, int index) {
      for (NERSpan ner : ners) {
        if (ner.end() - 1 == index)
          return true;
      }
      return false;
    }
  
    public static boolean isNominative(String govLemma, char normalPOS,
        WordNet wordnet) {
      if (normalPOS == 'n') {
        if (wordnet.isNominalization(govLemma)) {
          // System.out.println("isNominalization " + govLemma);
          return true;
        }
        if (wordnet.isNounEvent(govLemma)) {
          // System.out.println("isNounEvent " + govLemma);
          return true;
        }
      }
  
      return false;
    }
  
    /**
     * Determines if the given word index is the possessor in a possessive
     * relationship. This is either a "poss" reln, or a "prep_of" relation when
     * the index is a definite NP or an NER recognized (proper) noun.
     *
     * NOTE: For MUC, most important possessives are event nouns, so we could just
     * call isNominative and not this function.
     */
    public static boolean isPossessive(Tree tree, List<NERSpan> ners,
        Vector<TypedDependency> deps, int index) {
      Tree subtree = TreeOperator.indexToSubtree(tree, index);
      String posTag = subtree.label().value();
  
      if (posTag.startsWith("NN")) {
  
        for (TypedDependency dep : deps) {
          int depIndex = dep.dep().index();
          if (depIndex == index) {
            String reln = dep.reln().toString();
  
            if (reln.equals("poss"))
              return true;
  
            if (reln.equals("prep_of")) {
              if (isDefinite(deps, index) || isProper(ners, index)) {
                // String gov =
                // dep.gov().label().value().toString().toLowerCase();
                return true;
              }
            }
          }
        }
      }
      return false;
    }
  
    /**
     * Find all events that are syntactically dominated by the given event. This
     * finds the parse subtree where the given event is root, and returns all
     * events under that subtree.
     * 
     * @param sent
     *          The sentence in question.
     * @param event
     *          The event in question.
     * @return A List of TextEvents that are syntactically dominated.
     */
    public static List<TextEvent> getAllDominatedEvents(SieveSentence sent,
        TextEvent event) {
      List<TextEvent> dominated = new ArrayList<TextEvent>();
      Pair<Integer, Integer> dominatedTokenSpan = TreeOperator
          .tokenSpanUnderIndex(sent.getParseTree(), event.getIndex());
  
      for (TextEvent childEvent : sent.events()) {
        if (event != childEvent
            && childEvent.getIndex() >= dominatedTokenSpan.first()
            && childEvent.getIndex() < dominatedTokenSpan.second()) {
          dominated.add(childEvent);
        }
      }
      return dominated;
    }
  
    public static void main(String[] args) {
      System.out.println("88.4 " + Ling.isNumber("88.4"));
      System.out.println("47 1/2 " + Ling.isNumber("47 1/2"));
      System.out.println("a47 1/2 " + Ling.isNumber("a47 1/2"));
    }
  }
  