#!/usr/bin/env python ## $Id: constraint.py,v 1.3 2003/07/03 23:07:42 euske Exp $ ## ## constraint.py - Pattern matching / constraint checker ## import sys, re import pstring from regpat import PatternActionSet, PatCounter from sentence import Sentence, TextTokenizer, SentenceSplitter, POSTagger from abstfilter import AbstractFeeder, AbstractFilter, AbstractConsumer from document import HTMLProcessor, TexProcessor, PlainTextProcessor from unification import Unifier, UnificationError, forall, exists from postagfix import POSTagFixer from output import TerminalOutput from grammarerror import GrammarNounAgreementError, GrammarVerbAgreementError, GrammarNonDeterminerError def ispos(w, t): return w.pos_pref == t or (w.pos_pref == None and t in w.pos) class ParsePatternActionSet(PatternActionSet): def __init__(self, observer, warntypes, debug_action=False): self.debug_action = debug_action PatternActionSet.__init__(self) self.observer = observer self.check_determiner = "det" in warntypes self.check_plural = "plural" in warntypes return def compile_item0(self, t): return lambda w: not w.processed and ispos(w, t) def compile_item2(self, s): return lambda w: not w.processed and (not isinstance(w.s, Sentence)) and s.lower() == w.s.lower() def inherit_prop(self, m, inherit=None): if inherit: m.prop = inherit.prop m.prop.match = m else: m.prop = Unifier() return c = PatCounter().inc debug_action = True def action_wrapper(self, n, pat1, action, m): print "called:", n, map(str,m.getseq()) action(m) return ## CONSTRAINTS ## pat_det_pos = c('DT | DT1 | DTS | WDT | PRP$ | WP$') def act_det_pos(self, m): self.inherit_prop(m) w = m.submatch.item m.prop["determiner"] = True if ispos(w, "DT1"): m.prop["plural"] = False elif ispos(w, "DTS"): m.prop["plural"] = True return pat_pdts = c('PDT | PDT1 | PDTS') def act_pdts(self, m): self.inherit_prop(m) w = m.submatch.item if ispos(w, "PDT1"): m.prop["plural"] = False elif ispos(w, "PDTS"): m.prop["plural"] = True return pat_modifiers = c('CD | JJ | JJR | JJS | NN | NNR') pat_ng_3rdsing = c(' ? * (NN | NNR)') def act_ng_3rdsing(self, m): self.inherit_prop(m) m.prop["3rdsing"] = True return pat_ng_non3rdsing = c('? ? * NNS') def act_ng_non3rdsing(self, m): self.inherit_prop(m) m.prop["3rdsing"] = False return pat_pron = c('WP | PRP | PRP2 | PRPS') def act_pron(self, m): self.inherit_prop(m) w = m.submatch.item if ispos(w, "PRP2") or ispos(w, "PRPS"): m.prop["3rdsing"] = False elif ispos(w, "PRP"): m.prop["3rdsing"] = True return pat_ng = c(' | | ') def act_ng(self, m): self.inherit_prop(m, m.submatch) return pat_adv1 = c('RB') pat_there = c('"there" | "here"') pat_have1 = c('"have" | "\'ve"') pat_has1 = c('"has" | "\'s"') pat_had1 = c('"had" | "\'d"') pat_is1 = c('"is" | "isn\'t" | "\'s"') pat_are1 = c('"are" | "aren\'t" | "\'re"') pat_rel1 = c('"which" | "who" | "whom" | "that"') pat_vg_ven = c('VBN') pat_vg_ving = c('VBG | "being" ') pat_vg_perf = c('? | "been" ? | "been" ? ') # Verb group infinite - ignore pat_vg_inf = c('MD ? "be" | MD ? "be" | MD ? VB') def act_vg_inf(self, m): self.inherit_prop(m) return # Verb group past tense - ignore pat_vg_past = c(' | VBD') act_vg_past = act_vg_inf pat_vg_non3rdsing = c(' | | VBP') def act_vg_non3rdsing(self, m): self.inherit_prop(m) m.prop["3rdsing"] = False return pat_vg_3rdsing = c(' | | VBZ | ' + 'MDZ ? "be" | MDZ ? "be" | MDZ ? VB') def act_vg_3rdsing(self, m): self.inherit_prop(m) m.prop["3rdsing"] = True return pat_be_non3rdsing = c('"are" | "\'re" | "were" | "weren\'t"') act_be_non3rdsing = act_vg_non3rdsing pat_be_3rdsing = c('"is" | "isn\'t" | "\'s" | "was" | "wasn\'t"') act_be_3rdsing = act_vg_3rdsing pat_vg_there = c(' ( | )') def act_vg_there(self, m): self.inherit_prop(m, m.subseq[1].submatch) return pat_vg = c(' | | | ') def act_vg(self, m): self.inherit_prop(m, m.submatch) return pat_rel = c('IN? ') pat_pp = c('IN ') pat_sv1_check = c(' ? ? ? ') def act_sv1_check(self, m): self.check_sv(m, m.subseq[0], m.subseq[4]) return pat_sv2_check = c(' ? ? ') def act_sv2_check(self, m): self.check_sv(m, m.subseq[0], m.subseq[3]) return pat_sv3_check = c(' ') def act_sv3_check(self, m): self.check_sv(m, m.subseq[1], m.subseq[0]) return pat_ng_single = c('(? ?) (* (NN | NNR))') def act_ng_single(self, m): if exists(lambda w: w.processed, m.getseq()): return (mdet, mnoun) = (m.subseq[0], m.subseq[1]) if mdet.subseq[0].repseq: self.inherit_prop(m, mdet.subseq[0].repseq[0]) # inherit else: self.inherit_prop(m) w = mnoun.subseq[1].submatch.item if ispos(w, "NNR") or w.is_sent: m.prop["determiner"] = True if mdet.subseq[1].repseq: if self.check_ng(m, mdet, mnoun, mdet.subseq[1].repseq[0].prop["plural"]): return self.check_ng(m, mdet, mnoun, False) return pat_ng_plural = c('(? ?) (* NNS)') def act_ng_plural(self, m): if exists(lambda w: w.processed, m.getseq()): return (mdet, mnoun) = (m.subseq[0], m.subseq[1]) if mdet.subseq[0].repseq: self.inherit_prop(m, mdet.subseq[0].repseq[0]) # inherit else: self.inherit_prop(m) m.prop["determiner"] = True if mdet.subseq[1].repseq: if self.check_ng(m, mdet, mnoun, mdet.subseq[1].repseq[0].prop["plural"]): return self.check_ng(m, mdet, mnoun, True) return pat_ng_check = c(' | ') del c def check_sv(self, m, ms, mv): if exists(lambda w: w.processed, m.getseq()): return try: ms.prop.unify(mv.prop) except UnificationError: self.observer(GrammarVerbAgreementError(ms, mv)) for w in m.getseq(): w.processed = True return def check_ng(self, m, mdet, mnoun, plural): for w in m.getseq(): w.processed = True if self.check_plural: try: m.prop["plural"] = plural except UnificationError: self.observer(GrammarNounAgreementError(mdet, mnoun)) return True if self.check_determiner and not m.prop["determiner"]: self.observer(GrammarNonDeterminerError(m)) return True return False ## ## class ConstraintChecker(AbstractFilter): def __init__(self, next_filter, warntypes, debug_action=False): AbstractFilter.__init__(self, next_filter) self.actionset = ParsePatternActionSet(self.notify, warntypes, debug_action) self.warntypes = warntypes return def notify(self, e): self.feed_next((self.sent, e)) return def feed(self, sent): if sent.words[0].s == "[[": return for w in sent.words: if w.is_sent: self.feed(w.s) self.sent = sent if "sv1" in self.warntypes: self.actionset.perform_longest_first("sv1_check", sent.words) if "sv2" in self.warntypes: self.actionset.perform_longest_first("sv2_check", sent.words) if "sv3" in self.warntypes: self.actionset.perform_longest_first("sv3_check", sent.words) self.actionset.perform_longest_first("ng_check", sent.words) return # if __name__ == "__main__": if sys.argv[1] == "-t": docproc = TexProcessor elif sys.argv[1] == "-l": docproc = HTMLProcessor elif sys.argv[1] == "-p": docproc = PlainTextProcessor else: assert 0 import dictionary dict = dictionary.Dictionary("LOCAL/dict.txt") out = TerminalOutput() pipeline = docproc(TextTokenizer(SentenceSplitter(POSTagger(dict, POSTagFixer(ConstraintChecker(out, ["sv1","sv2","sv3","det","plural"])))))) pipeline.read(pstring.PFile(sys.stdin))