RJ3vans commited on
Commit
2dbcc55
·
verified ·
1 Parent(s): 8dea49d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +84 -32
app.py CHANGED
@@ -1902,14 +1902,30 @@ MODAL_MID = {
1902
  "certainly", "definitely", "simply", "almost",
1903
  }
1904
  ###############################################################################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1905
 
1906
  ###############################################################################
1907
  def fix_subject_verb_agreement(sent: str) -> str:
1908
  """
1909
  After a split, repair a finite verb / aux that no longer matches
1910
  a singular subject.
1911
- Do not touch infinitives (to be, to go, …), modal complements
1912
- (may have, will go), or already-singular forms.
1913
  """
1914
  if not sent or not sent.strip():
1915
  return sent
@@ -1946,33 +1962,53 @@ def fix_subject_verb_agreement(sent: str) -> str:
1946
  return True
1947
  return False
1948
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1949
  def in_bare_infinitive_complement(tok) -> bool:
1950
- """
1951
- Bare infinitive after a modal or do-support, allowing
1952
- intervening negation / adverbs:
1953
-
1954
- may not even have
1955
- didn't want
1956
- does not go
1957
- will really be
1958
- """
1959
  i = tok.i - 1
1960
  while i >= 0:
1961
  t = doc[i]
1962
- if t.tag_ == "MD" or t.lemma_.lower() in MODALS or t.lower_ in MODALS:
1963
- return True
1964
- if t.lemma_ == "do" and t.lower_ in {"do", "does", "did"}:
1965
  return True
 
1966
  if (
1967
  t.lower_ in MODAL_MID
 
1968
  or t.dep_ in {"neg", "advmod", "punct"}
1969
  or t.pos_ in {"ADV", "PART", "PUNCT", "SPACE"}
 
1970
  ):
1971
  i -= 1
1972
  continue
1973
  return False
1974
  return False
1975
 
 
 
 
 
 
 
 
 
 
 
 
1976
  def to_3sg(word: str) -> str:
1977
  low = word.lower()
1978
  irregular = {
@@ -1996,18 +2032,6 @@ def fix_subject_verb_agreement(sent: str) -> str:
1996
  new = new[0].upper() + new[1:]
1997
  return new
1998
 
1999
- def skip_target(t) -> bool:
2000
- if t.tag_ == "MD":
2001
- return True
2002
- if is_infinitive(t):
2003
- return True
2004
- if in_bare_infinitive_complement(t):
2005
- return True
2006
- # infinitival / base be must never get -s
2007
- if t.lemma_ == "be" and t.lower_ in {"be", "bes", "beses"}:
2008
- return True
2009
- return False
2010
-
2011
  target = None
2012
  for t in doc:
2013
  if skip_target(t):
@@ -2026,13 +2050,41 @@ def fix_subject_verb_agreement(sent: str) -> str:
2026
  target = t
2027
  break
2028
 
2029
- if target is None:
2030
- return sent
2031
- if target.lower_ in {"is", "was", "has", "does", "be"}:
2032
- return sent
2033
 
2034
- new = to_3sg(target.text)
2035
- return sent[: target.idx] + new + sent[target.idx + len(target.text) :]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2036
  ###############################################################################
2037
 
2038
  ###############################################################################
 
1902
  "certainly", "definitely", "simply", "almost",
1903
  }
1904
  ###############################################################################
1905
+ # do-support / modal on the raw string to the left of the verb
1906
+ _LEFT_BARE_INF = re.compile(
1907
+ r"(?:"
1908
+ r"\b(?:can|could|may|might|must|shall|should|will|would)\b|"
1909
+ r"\b(?:do|does|did)\b|"
1910
+ r"\b(?:don't|doesn't|didn't|don’t|doesn’t|didn’t)\b|"
1911
+ r"\b(?:do|does|did)\s+not\b|"
1912
+ r"\b(?:don|doesn|didn)\s*['’]\s*t\b"
1913
+ r")"
1914
+ r"(?:\s+\b(?:not|even|never|also|really|just|only|still|"
1915
+ r"already|always|actually|probably|possibly|perhaps|"
1916
+ r"certainly|definitely|simply|almost)\b)*"
1917
+ r"\s+$",
1918
+ flags=re.I,
1919
+ )
1920
+ ###############################################################################
1921
 
1922
  ###############################################################################
1923
  def fix_subject_verb_agreement(sent: str) -> str:
1924
  """
1925
  After a split, repair a finite verb / aux that no longer matches
1926
  a singular subject.
1927
+ Never inflect a bare infinitive after a modal or do-support
1928
+ (may have, didn't want, didn ' t want).
1929
  """
1930
  if not sent or not sent.strip():
1931
  return sent
 
1962
  return True
1963
  return False
1964
 
1965
+ def is_do_aux(t) -> bool:
1966
+ low = re.sub(r"[^a-z]", "", t.lower_)
1967
+ if t.lemma_ == "do":
1968
+ return True
1969
+ return low in {
1970
+ "do", "does", "did",
1971
+ "dont", "doesnt", "didnt",
1972
+ "don", "doesn", "didn",
1973
+ }
1974
+
1975
+ def is_modal(t) -> bool:
1976
+ return t.tag_ == "MD" or t.lemma_.lower() in MODALS or t.lower_ in MODALS
1977
+
1978
  def in_bare_infinitive_complement(tok) -> bool:
1979
+ left = sent[: tok.idx]
1980
+ if _LEFT_BARE_INF.search(left):
1981
+ return True
1982
+
 
 
 
 
 
1983
  i = tok.i - 1
1984
  while i >= 0:
1985
  t = doc[i]
1986
+ if is_modal(t) or is_do_aux(t):
 
 
1987
  return True
1988
+ frag = re.sub(r"[^a-z]", "", t.lower_)
1989
  if (
1990
  t.lower_ in MODAL_MID
1991
+ or frag in {"", "t", "nt", "n"}
1992
  or t.dep_ in {"neg", "advmod", "punct"}
1993
  or t.pos_ in {"ADV", "PART", "PUNCT", "SPACE"}
1994
+ or t.text in {"'", "’", "‘"}
1995
  ):
1996
  i -= 1
1997
  continue
1998
  return False
1999
  return False
2000
 
2001
+ def skip_target(t) -> bool:
2002
+ if t.tag_ == "MD":
2003
+ return True
2004
+ if is_infinitive(t):
2005
+ return True
2006
+ if in_bare_infinitive_complement(t):
2007
+ return True
2008
+ if t.lemma_ == "be" and t.lower_ in {"be", "bes", "beses"}:
2009
+ return True
2010
+ return False
2011
+
2012
  def to_3sg(word: str) -> str:
2013
  low = word.lower()
2014
  irregular = {
 
2032
  new = new[0].upper() + new[1:]
2033
  return new
2034
 
 
 
 
 
 
 
 
 
 
 
 
 
2035
  target = None
2036
  for t in doc:
2037
  if skip_target(t):
 
2050
  target = t
2051
  break
2052
 
2053
+ out = sent
2054
+ if target is not None and target.lower_ not in {"is", "was", "has", "does", "be"}:
2055
+ new = to_3sg(target.text)
2056
+ out = sent[: target.idx] + new + sent[target.idx + len(target.text) :]
2057
 
2058
+ # Safety net: if a 3sg form still sits after do-support / a modal,
2059
+ # put it back to the lemma (wants→want, has→have, goes→go).
2060
+ doc2 = nlp(out)
2061
+ for t in reversed(list(doc2)):
2062
+ if t.lemma_ == "do" or t.tag_ == "MD":
2063
+ continue
2064
+ left = out[: t.idx]
2065
+ if not _LEFT_BARE_INF.search(left):
2066
+ continue
2067
+ if t.tag_ != "VBZ" and t.lower_ not in {
2068
+ "wants", "goes", "has", "does", "is", "lives",
2069
+ }:
2070
+ continue
2071
+ base = t.lemma_ if t.lemma_ and t.lemma_ != "-PRON-" else t.text
2072
+ if t.lower_ == "has":
2073
+ base = "have"
2074
+ elif t.lower_ == "is":
2075
+ base = "be"
2076
+ elif t.lower_ == "does":
2077
+ base = "do"
2078
+ elif t.lower_ == "goes":
2079
+ base = "go"
2080
+ elif t.lower_.endswith("s") and t.lemma_:
2081
+ base = t.lemma_
2082
+ if base.lower() == t.lower_:
2083
+ continue
2084
+ if t.text[:1].isupper():
2085
+ base = base[0].upper() + base[1:]
2086
+ out = out[: t.idx] + base + out[t.idx + len(t.text) :]
2087
+ return out
2088
  ###############################################################################
2089
 
2090
  ###############################################################################