All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.languagetool.rules.uk.TokenAgreementVerbNounExceptionHelper Maven / Gradle / Ivy

The newest version!
package org.languagetool.rules.uk;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.languagetool.AnalyzedToken;
import org.languagetool.AnalyzedTokenReadings;
import org.languagetool.rules.uk.LemmaHelper.Dir;
import org.languagetool.rules.uk.RuleException.Type;
import org.languagetool.rules.uk.SearchHelper.Condition;
import org.languagetool.rules.uk.TokenAgreementVerbNounRule.State;
import org.languagetool.rules.uk.VerbInflectionHelper.Inflection;
import org.languagetool.tagging.uk.PosTagHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @since 5.9
 */
public final class TokenAgreementVerbNounExceptionHelper {

  private static final Logger logger = LoggerFactory.getLogger(TokenAgreementVerbNounExceptionHelper.class);

  private static final Pattern VCHYTY_PATTERN = Pattern.compile(".*вч[аи]ти(ся)?");
  private static final Pattern ADV_PREDICT_PATTERN = Pattern.compile("(adv|noninfl:&predic).*");

  private static final Pattern MODALS_ADJ = Pattern.compile("змушений|вимушений|повинний|здатний|готовий|ладний|радий");
  
  private TokenAgreementVerbNounExceptionHelper() {
  }

  public static boolean isException(AnalyzedTokenReadings[] tokens, 
                                    State state, List verbInflections, 
                                    List nounAdjInflections,
                                    List verbTokenReadings, 
                                    List nounTokenReadings) {
    
    int verbPos = state.verbPos;
    int nounAdjPos = state.nounPos;

    String cleanTokenLower = tokens[nounAdjPos].getCleanToken().toLowerCase();

    // боротиметься кілька однопартійців
    // входило двоє студентів
    if( (PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("numr.*v_naz.*"))
            || LemmaHelper.hasLemma(tokens[nounAdjPos], LemmaHelper.ADV_QUANT_PATTERN, Pattern.compile("noun.*v_naz.*|adv.*|part.*"))) ) {
      if( PosTagHelper.hasPosTag(state.verbAnalyzedTokenReadings, Pattern.compile(".*:[sn](:.*|$)")) ) {
        logException();
        return true; 
      }
      // буде лежати двоє хворих
      if( verbPos > 1 
          && PosTagHelper.hasPosTag(state.verbAnalyzedTokenReadings, Pattern.compile("verb.*inf.*"))
          && LemmaHelper.hasLemma(tokens[verbPos-1], Pattern.compile("бути|мусити"), Pattern.compile("verb.*(past:n|:s:3).*")) ) {
        logException();
        return true; 
      }
    }

    if( verbPos > 1
        && LemmaHelper.hasLemma(tokens[verbPos], "бути") ) {
      // здатна була
      if( LemmaHelper.hasLemma(tokens[verbPos-1], TokenAgreementVerbNounExceptionHelper.MODALS_ADJ, Pattern.compile("adj:.:v_naz.*")) ) {
          // повинен був випадок передбачити
//          && agrees(tokens[verbPos], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) ) {
        logException();
        return true; 
      }
    }

    // TODO: temp: коли зможе силою розуму освоїти
    if( LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile("з?могти"))
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], ".*v_oru.*") ) {
      logException();
      return true; 
    }
    
    // чим могла
    if( verbPos > 1
        && LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile("з?могти"))
        && tokens[verbPos-1].getCleanToken().toLowerCase().equals("чим") ) {
      logException();
      return true; 
    }
    
    // хоче маляром
    if( LemmaHelper.hasLemma(tokens[verbPos], "хотіти") 
        && PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_oru") ) {
      logException();
      return true; 
    }

    // має своїм неодмінним наслідком
    if( LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile("мати|маючи|мавши"))
//        && new SearchHelper.Match()
//          .target(new Condition(Pattern.compile("наслідок|результат|принцип|підґрунтя|виток|причина|коріння|ідеал"), Pattern.compile(".*v_oru.*")))
//          .skip(Condition.postag(Pattern.compile("(.*v_oru|part|adv).*")))
//          .limit(4)
//          .mAfter(tokens, nounAdjPos) >= 0
        && PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_oru")
        ) {
      logException();
      return true; 
    }

    // були б іншої думки/такого змісту
    if( LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile("бути"))
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], "(adj|numr).*v_rod.*") ) {
      logException();
      return true; 
    }
    
    // що є сил
    if( verbPos > 1
        && tokens[verbPos-1].getCleanToken().toLowerCase().equals("що")
        && LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile("бути"), Pattern.compile("verb.*(:s:3|past:n).*"))
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], "(adj|noun).*v_rod.*") ) {
      logException();
      return true; 
    }

    // навіщо було город городити
    if( verbPos > 1
        && tokens[verbPos].getCleanToken().toLowerCase().equals("було")
        && tokens[verbPos-1].getCleanToken().toLowerCase().equals("навіщо") ) {
      logException();
      return true; 
    }

    // чесніше було б державний фонд
    if( verbPos > 1
        && tokens[verbPos].getCleanToken().toLowerCase().equals("було")
        && PosTagHelper.hasPosTag(tokens[verbPos-1], "(adv:comp[cs].*|.*predic.*)") ) {
      logException();
      return true; 
    }

    if( verbPos > 2
        && tokens[verbPos].getCleanToken().toLowerCase().equals("було")
        && tokens[verbPos-1].getCleanToken().toLowerCase().matches("би?")
        && PosTagHelper.hasPosTag(tokens[verbPos-2], "(adv:comp[cs].*|.*predic.*)") ) {
      logException();
      return true; 
    }
    
    // квітне притухлий було пафос
    if( verbPos > 1
        && tokens[verbPos].getCleanToken().toLowerCase().equals("було")
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile(".*v_naz.*"))      // may be not just for v_naz
        && PosTagHelper.hasPosTag(tokens[verbPos-1], "adj:.:v_naz:&adjp:.*:perf.*") ) { // may be not just for v_naz
      logException();
      return true; 
    }

    // підстрахуватися не зайве
    if( // tokens[verbPos].getCleanToken().toLowerCase().matches("було|буде")
        cleanTokenLower.matches("зайве|резон") ) {
      logException();
      return true; 
    }

    // було всі 90-ті
    if( tokens[verbPos].getCleanToken().toLowerCase().matches("було|буде")
        && LemmaHelper.hasLemma(tokens[nounAdjPos], Arrays.asList("весь"), Pattern.compile(".*v_zna.*")) ) {
      logException();
      return true; 
    }

    // буде видно тільки супутники
    if( tokens[verbPos].getCleanToken().toLowerCase().matches("було|буде")
      && new SearchHelper.Match()
        .target(Condition.postag(Pattern.compile(".*predic.*")))
        .limit(nounAdjPos-verbPos)
        .mAfter(tokens, verbPos+1) >= 0 ) {
      logException();
      return true; 
    }

    // потрібно буде ше склянку
    if( tokens[verbPos].getCleanToken().toLowerCase().matches("було|буде")
      && new SearchHelper.Match()
        .target(Condition.lemma(Pattern.compile("треба|потрібно")))
        .mNow(tokens, verbPos-1) >= 0 ) {
      logException();
      return true; 
    }
    
    // він був талановита людина
    if( tokens[verbPos].getCleanToken().toLowerCase().equals("був") ) {
      if (tokens[nounAdjPos].getCleanToken().toLowerCase().matches("людина|знаменитість")) {
        logException();
        return true; 
      }
      if ( nounAdjPos < tokens.length -1 
          && tokens[nounAdjPos+1].getCleanToken().toLowerCase().matches("людина")) {
        logException();
        return true; 
      }
    }
    
    // Конкурс був десь шість
    if( verbPos > 1
        && tokens[verbPos-1].getCleanToken().toLowerCase().equals("конкурс")
        && LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile("бути"), Pattern.compile("verb.*(:s:3|past:m).*"))
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("num.*")) ) {
      logException();
      return true; 
    }

    // розподілятиметься пропорційно вкладеній праці
    if( nounAdjPos - verbPos > 1 ) {
      Set advReq = CaseGovernmentHelper.getCaseGovernments(tokens[nounAdjPos-1], Pattern.compile("adv(?!p).*"));
      if( advReq.size() > 0 ) {
        for(int ii=verbPos+1; ii 3 
        && tokens[verbPos].getCleanToken().equalsIgnoreCase("впало")
        && "ні".equals(tokens[verbPos-1].getCleanToken()) ) {
      logException();
      return true;
    }
    // звичайна, якщо не сказати слабка, людина
    if( verbPos > 2
        && tokens[verbPos].getCleanToken().equalsIgnoreCase("сказати")
        && "не".equals(tokens[verbPos-1].getCleanToken())
        && PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_naz") ) {
      logException();
      return true;
    }
    
    // потребувала мільйон
    if( state.cases.contains("v_rod")
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("numr.*?v_zna.*|noun.*v_zna.*numr.*")) ) {
      logException();
      return true;
    }
    
    // виростили сортів 10
    if( nounAdjPos < tokens.length - 1
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("(noun|adj):.*:v_rod.*")) 
        && PosTagHelper.hasPosTag(tokens[nounAdjPos+1], Pattern.compile("num.*"))
        ) {
      logException();
      return true;
    }
    
    // виростили сортів — 10
    if( nounAdjPos < tokens.length - 2
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("(noun|adj):.*:v_rod.*")) 
        && LemmaHelper.isDash(tokens[nounAdjPos+1])
        && PosTagHelper.hasPosTag(tokens[nounAdjPos+2], Pattern.compile("num.*"))
        ) {
      logException();
      return true;
    }
    
    // одержав хабарів на суму 10
    if( nounAdjPos < tokens.length - 2
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("(noun:inanim|adj):.:v_rod.*")) ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.nounPos+1, (Pattern)null, Pattern.compile("на"), Pattern.compile("[a-z].*"), Dir.FORWARD);
      if( v2pos >= 0 && v2pos <= state.nounPos+5 && v2pos < tokens.length - 1 ) {
        logException();
        return true;
      }
    }

    // залучити інвестицій на 20—30
    if( nounAdjPos < tokens.length - 2 
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("noun.*v_(rod|zna).*"))
        && tokens[nounAdjPos+1].getCleanToken().matches("на|з|із|зо|під")
        && PosTagHelper.hasPosTag(tokens[nounAdjPos+2], Pattern.compile("number|numr.*v_zna.*")) ) {
      logException();
      return true;
    }

    // V_DAV
    if( PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_dav") ) {

      // INF + V_DAV
      if( PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf") ) {

        // як боротися підприємцям
        if( verbPos > 1 
            && LemmaHelper.hasLemma(tokens[verbPos-1], Arrays.asList("як", "куди", "де", "що", "чого", "чи"))) {
          logException();
          return true;
        }
        // Квапитися їй нікуди
        if( nounAdjPos < tokens.length -1
            && tokens[nounAdjPos+1].getCleanToken().toLowerCase().matches("ніколи|нікуди|нічого|нічим|ніде|немає?|не")) {
          logException();
          return true;
        }

        // тут жити мешканцям було б добре
        if( LemmaHelper.hasLemma(tokens[verbPos], Arrays.asList("жити", "сидіти", "судити"))) {
          logException();
          return true;
        }
        // нічим пишатися селянам
        // TODO: нікуди було діватися поліції
        if( verbPos > 1
            && tokens[verbPos-1].getCleanToken().toLowerCase().matches("ніколи|нікуди|нічого|нічим|ніде|де|немає?|не")) {
          logException();
          return true;
        }

        // не бачити вам цирку
        if( verbPos > 1 && nounAdjPos < tokens.length - 1
            && tokens[verbPos-1].getCleanToken().toLowerCase().matches("не|а?ні")
            && PosTagHelper.hasPosTagPart(tokens[nounAdjPos+1], "v_rod") ) {
          logException();
          return true;
        }

        // слід проходити людям
        if( verbPos > 1
            && tokens[verbPos-1].getCleanToken().toLowerCase().matches("слід|снаги|силу")) {
          logException();
          return true;
        }
      }

      // розсміявся брату в обличчя
      if( nounAdjPos < tokens.length - 2
          && tokens[nounAdjPos+1].getCleanToken().toLowerCase().matches("в|у|на|від|під|по|до|і?з|з[іо]|над|з-під|перед|попід|поза|напереріз")
          && PosTagHelper.hasPosTag(tokens[nounAdjPos+2], Pattern.compile("(noun|adj).*"))) {
        logException();
        return true;
      }
      if( nounAdjPos < tokens.length - 1
          && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile(".*v_dav.*"))
          && tokens[nounAdjPos+1].getCleanToken().toLowerCase().matches("назустріч|навперейми|навздогін|услід")) {
        logException();
        return true;
      }

      // закружляли мені десь у тьмі
      if( nounAdjPos < tokens.length - 2
          && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("noun.*?v_dav:&pron:(pers|refl).*"))) {
        logException();
        return true;
      }
    }

    // сміятися гріх
    if( PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        && tokens[nounAdjPos].getCleanToken().equalsIgnoreCase("гріх") ) {
      logException();
      return true;
    }

    // тренувалися годину
    // працювала рік-два
//    if( LemmaHelper.hasLemmaBase(tokens[nounAdjPos], LemmaHelper.TIME_PLUS_LEMMAS, Pattern.compile("noun:inanim:.:v_(zna|rod|oru).*"))) {
//      logException();
//      return true;
//    }
//
    // відбудеться наступного дня
//    if( nounAdjPos < tokens.length - 1 
//        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("(adj|numr).*v_(rod|zna|oru).*|noun.*v_(rod|zna|oru).*numr.*"))
//        && LemmaHelper.hasLemma(tokens[nounAdjPos+1], LemmaHelper.TIME_PLUS_LEMMAS, Pattern.compile("noun:inanim:.:v_(rod|zna|oru).*"))) {
//      logException();
//      return true;
//    }

    // відбувається кожні два роки
    // розпочнеться того ж дня
    if( 
//        nounAdjPos < tokens.length - 2 
//        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("(adj|numr).*v_(rod|zna|oru).*"))
//        && (tokens[nounAdjPos+1].getCleanToken().matches("же?")
//         || PosTagHelper.hasPosTag(tokens[nounAdjPos+1], Pattern.compile("(adj|numr).*v_(rod|zna|oru).*|number|noun.*v_(rod|zna|oru).*numr.*")))
//        && LemmaHelper.hasLemma(tokens[nounAdjPos+2], LemmaHelper.TIME_PLUS_LEMMAS, Pattern.compile("noun:inanim:.:v_(rod|zna|oru).*"))) {
      
      new SearchHelper.Match()
          .skip(Condition.postag(Pattern.compile(".*v_(rod|zna|oru).*|part.*|number")))
         .target(Condition.lemma(LemmaHelper.TIME_PLUS_LEMMAS_PATTERN))
         .limit(4)
         .mAfter(tokens, nounAdjPos) > 0 ) {
      
      logException();
      return true;
    }

    // йде три з половиною години
    if( nounAdjPos < tokens.length - 3 
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("numr.*v_zna.*"))
//        && tokens[nounAdjPos+1].getCleanToken().matches("з")
//        && tokens[nounAdjPos+2].getCleanToken().matches("половиною")
//        && LemmaHelper.hasLemma(tokens[nounAdjPos+3], LemmaHelper.TIME_PLUS_LEMMAS, Pattern.compile("noun:inanim:.:v_(rod|zna).*"))) {
        && new SearchHelper.Match().target(Condition.lemma(LemmaHelper.TIME_PLUS_LEMMAS_PATTERN))
            .limit(4)
            .mAfter(tokens, nounAdjPos+1) > 0 ) {
      logException();
      return true;
    }

    if( new SearchHelper.Match()
        .skip(Condition.postag(Pattern.compile(".*v_oru.*|part.*|adv.*")))
        .target(new Condition(Pattern.compile("мова"), Pattern.compile("noun:inanim:.:v_oru.*")))
        .limit(4)
        .mAfter(tokens, nounAdjPos) > 0 ) {

      logException();
      return true;
    }

    // став жовтого кольору
    if( nounAdjPos < tokens.length - 1
        && tokens[nounAdjPos + 1].getCleanToken().toLowerCase().equals("кольору")
        && PosTagHelper.hasPosTagStart(tokens[nounAdjPos], "adj:m:v_rod")) {
      logException();
      return true;
    }

    // дай Боже
    if( PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_kly")
        && PosTagHelper.hasPosTagPart(tokens[verbPos], "impr")) {
      logException();
      return true;
    }

    // повторила прем’єр-міністр у телезверненні
    if( PosTagHelper.hasPosTagPart(nounTokenReadings, "noun:anim:m:v_naz")
        && PosTagHelper.hasPosTag(verbTokenReadings, Pattern.compile("verb.*:f(:.*|$)"))
        && TokenAgreementNounVerbExceptionHelper.hasMascFemLemma(nounTokenReadings) ) {
      logException();
      return true;
    }

    // не існувало конкуренції
    // не було мізків
    // стане сили
    // TODO: все залежить нас
    if( PosTagHelper.hasPosTagPart(tokens[state.nounPos], "v_rod")
        && PosTagHelper.hasPosTag(state.verbTokenReadings, Pattern.compile("verb.*?(futr|past):(s:3.*|n($|:.+))"))) {
      logException();
      return true;
    }

    // меншає людей
    if( LemmaHelper.hasLemma(state.verbAnalyzedTokenReadings, Pattern.compile("(по)?меншати|(по)?більшати|стати"), Pattern.compile("verb.*:[sn](:.*|$)"))
        && PosTagHelper.hasPosTag(tokens[state.nounPos], Pattern.compile("(noun|adj).*v_rod.*")) ) {
      logException();
      return true;
    }

    // споживає газу менше
    if( nounAdjPos < tokens.length - 1
        &&  PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("noun:.*v_rod.*")) 
        && tokens[nounAdjPos+1].getCleanToken().matches("менше|більше")
        ) {
      logException();
      return true;
    }

    // небагато надходить книжок
    // трохи зменшується матерії
    if( state.verbPos > 1
        && PosTagHelper.hasPosTagPart(tokens[state.nounPos], "v_rod") ) {

      Pattern vRodDriverPattern = Pattern.compile("не|(на)?с[кт]ільки|(най)?більше|(най)?менше|(не|за)?багато|(не|чи|за)?мало|трохи|годі|неможливо|а?ніж|вдосталь|купу", Pattern.CASE_INSENSITIVE|Pattern.UNICODE_CASE);
      int xpos = LemmaHelper.tokenSearch(tokens, state.verbPos-1, (String)null, vRodDriverPattern, Pattern.compile("[a-z].*"), Dir.REVERSE);
      if( xpos >= 0 && xpos >= state.verbPos-4 ) {
          logException();
          return true;
      }
    }
    
    // V + N + V:INF
    // вміємо цим зазвичай користуватися
    if( nounAdjPos < tokens.length - 1
        && CaseGovernmentHelper.hasCaseGovernment(state.verbAnalyzedTokenReadings, PosTagHelper.VERB_ADVP_PATTERN, "v_inf") ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.nounPos+1, PosTagHelper.VERB_PATTERN, null, Pattern.compile("[a-z].*"), Dir.FORWARD);
      if( v2pos >= 0 && v2pos <= state.nounPos+5
          && agrees(tokens[v2pos], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) 
          ) {
        logException();
        return true;
      }
    }
    
    // V:INF + N + V
    // працювати ці люди не вміють
    // робити прогнозів не буду
    if( nounAdjPos < tokens.length - 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf") ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.nounPos+1, PosTagHelper.VERB_PATTERN, null, Pattern.compile("[a-z].*"), Dir.FORWARD);
      if( v2pos >= 0 && v2pos <= state.nounPos+4
          && CaseGovernmentHelper.hasCaseGovernment(tokens[v2pos], PosTagHelper.VERB_PATTERN, "v_inf") ) { 
        if( agrees(tokens[v2pos], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) ) { 
          logException();
          return true;
        }
        if( tokens[v2pos-1].getCleanToken().equals("не") ) { 
          logException();
          return true;
        }
      }
    }
    
    // ADVP + N + V
    // резюмуючи політик наголосив
    if( nounAdjPos < tokens.length - 1
        && PosTagHelper.hasPosTagStart(tokens[verbPos], "advp") ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.nounPos+1, PosTagHelper.VERB_PATTERN, null, Pattern.compile("[a-z].*"), Dir.FORWARD);
      if( v2pos >= 0 && v2pos <= state.nounPos+3 ) { 
        if( agrees(tokens[v2pos], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) ) { 
          logException();
          return true;
        }
      }
    }
    
    // V + ADVP + N
    // пригадує посміхаючись Аскольд - only: сміючись, посміхаючись; if more generic hides TP
    // TP: знищила існуючи бази даних
    if( verbPos > 1
        && PosTagHelper.hasPosTagStart(tokens[verbPos], "advp")
        && Arrays.asList("посміхаючись", "сміючись").contains(tokens[verbPos].getCleanToken())
        && PosTagHelper.hasPosTagStart(tokens[verbPos-1], "verb")) {
      if( agrees(tokens[verbPos-1], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) ) { 
        logException();
        return true;
      }
    }

    // V:INF + N + ADV
    // розібратися людям важко
    if( nounAdjPos < tokens.length - 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf") ) {
      
      if( ! LemmaHelper.hasLemma(tokens[verbPos], VCHYTY_PATTERN) ) {
        int v2pos = LemmaHelper.tokenSearch(tokens, state.nounPos+1, ADV_PREDICT_PATTERN, null, Pattern.compile("[a-z].*"), Dir.FORWARD);
        while( v2pos >= 0 && v2pos <= state.nounPos+4 ) {
          Set cases = CaseGovernmentHelper.getCaseGovernments(tokens[v2pos], ADV_PREDICT_PATTERN);
          if( TokenAgreementPrepNounRule.hasVidmPosTag(cases, state.nounAdjIndirTokenReadings) ) {
            logException();
            return true;
          }
          v2pos = LemmaHelper.tokenSearch(tokens, v2pos+1, ADV_PREDICT_PATTERN, null, Pattern.compile("[a-z].*"), Dir.FORWARD);
        }
      }
    }

    // V:INF + N + ADJ
    // працювати студенти готові
    if( nounAdjPos < tokens.length - 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf") ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.nounPos+1, PosTagHelper.ADJ_V_NAZ_PATTERN, null, Pattern.compile("[a-z].*"), Dir.FORWARD);
      if( v2pos >= 0 && v2pos <= state.nounPos+3 ) {
        if( CaseGovernmentHelper.hasCaseGovernment(tokens[v2pos], PosTagHelper.ADJ_V_NAZ_PATTERN, "v_inf") ) {
          String genders1 = PosTagHelper.getGenders(tokens[nounAdjPos], "(noun|adj).*v_naz.*");
          String genders2 = PosTagHelper.getGenders(tokens[v2pos], PosTagHelper.ADJ_V_NAZ_PATTERN);
          if( genders1.matches(".*["+genders2+"].*") ) {
            logException();
            return true;
          }
        }
      }
    }

    // V:INF + ADJ
    // працювати неспроможні
    if( PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], PosTagHelper.ADJ_V_NAZ_PATTERN) ) {
      if( CaseGovernmentHelper.hasCaseGovernment(tokens[nounAdjPos], PosTagHelper.ADJ_V_NAZ_PATTERN, "v_inf") ) {
        logException();
        return true;
      }
    }

    // V + V:INF + N
    // дають (змогу з комфортом) мандрувати чотирьом пасажирам
    // заважають розвиватися погане управління, війна
    if( verbPos > 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        ) {

      int lookupPos = state.verbPos-1;

      // перестають діяти й розвиватися демократичні
      if( verbPos > 3 ) {
        if( LemmaHelper.hasLemma(tokens[verbPos-1], Arrays.asList("і", "й", "та"))
            && PosTagHelper.hasPosTagPart(tokens[verbPos-2], ":inf") ) {
          lookupPos = verbPos - 3;
        }
      }
      
      int v2pos = LemmaHelper.tokenSearch(tokens, lookupPos, PosTagHelper.VERB_ADVP_PATTERN, null, Pattern.compile("[a-z].*"), Dir.REVERSE);
      if( v2pos >= 0 && v2pos >= state.verbPos-5
          && (CaseGovernmentHelper.hasCaseGovernment(tokens[v2pos], PosTagHelper.VERB_ADVP_PATTERN, "v_inf") 
            || tokens[verbPos].getCleanToken().matches("(по)?їсти")) 
          ) {
        if( agrees(tokens[v2pos], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) ) {
          logException();
          return true;
        }
        // заважають розвиватися погане управління, війна
        if( PosTagHelper.hasPosTag(tokens[v2pos], Pattern.compile("verb.*:p($|:.*)")) 
            && PosTagHelper.hasPosTag(tokens[state.nounPos], Pattern.compile(".*v_naz.*")) ) {
          logException();
          return true;
        }
      }
    }
    
    // ADV + V:INF + N
    // важко розібратися багатьом людям
    if( verbPos > 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.verbPos-1, ADV_PREDICT_PATTERN, null, Pattern.compile("[a-z].*"), Dir.REVERSE);
      while( v2pos >= 0 && v2pos >= state.verbPos-3 ) {
        if( PosTagHelper.hasPosTag(tokens[v2pos], Pattern.compile("noninfl.&predic.*")) 
            && PosTagHelper.hasPosTagPart(tokens[state.nounPos], "v_naz") 
           ){
          logException();
          return true;
        }
        Set cases = CaseGovernmentHelper.getCaseGovernments(tokens[v2pos], ADV_PREDICT_PATTERN);
        if( TokenAgreementPrepNounRule.hasVidmPosTag(cases, state.nounAdjIndirTokenReadings) ) {
          logException();
          return true;
        }
        v2pos = LemmaHelper.tokenSearch(tokens, v2pos-1, ADV_PREDICT_PATTERN, null, Pattern.compile("[a-z].*"), Dir.REVERSE);
      }
    }
    
    // ADJ + V:INF + N
    // зацікавлена перейняти угорська сторона
    if( verbPos > 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        && PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_naz")
        ) {
      // не в змозі приховати офіційна статистика
      if( tokens[verbPos-1].getCleanToken().toLowerCase().matches("змозі|змогу|силі|силах") ) { // але "під силу" + v_dav
        logException();
        return true;
      }

      int v2pos = LemmaHelper.tokenSearch(tokens, state.verbPos-1, PosTagHelper.ADJ_V_NAZ_PATTERN, null, Pattern.compile("[a-z].*"), Dir.REVERSE);
      if( v2pos >= 0 && v2pos >= state.verbPos-3 ) {
        if( CaseGovernmentHelper.hasCaseGovernment(tokens[v2pos], PosTagHelper.ADJ_V_NAZ_PATTERN, "v_inf") ) {
          String genders1 = PosTagHelper.getGenders(tokens[nounAdjPos], "(noun|adj|numr).*v_naz.*");
          String genders2 = PosTagHelper.getGenders(tokens[v2pos], PosTagHelper.ADJ_V_NAZ_PATTERN);
          if( genders1.matches(".*["+genders2+"].*") ) {
            logException();
            return true;
          }
        }
      }
    }
    
    // ADJ + бути + N
    if( verbPos > 1
        && LemmaHelper.hasLemma(tokens[verbPos], "бути") 
        && PosTagHelper.hasPosTag(tokens[verbPos-1], "adj:.:v_naz.*")
//        && agrees(tokens[verbPos], tokens[verbPos-1])
        && CaseGovernmentHelper.hasCaseGovernment(tokens[verbPos-1], "v_rod") 
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("(adj|noun).*v_rod.*"))
        ) {
      logException();
      return true;
    }

    // V:IMPERS + бути + N
    if( verbPos > 1
        && LemmaHelper.hasLemma(tokens[verbPos], "бути") 
        && PosTagHelper.hasPosTag(tokens[verbPos-1], "verb.*impers.*")
        && agrees(tokens[verbPos-1], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings)
        ) {
      logException();
      return true;
    }

    // NOUN + V:INF + N
    // гріх зайнятися Генеральній прокуратурі
    // готовність спілкуватися людини
    // небажання вибачатися пов’язане з
    if( verbPos > 1
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        && (PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_dav") || PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_rod")
            || PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("adj:.:v_naz.*")))
        ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.verbPos-1, PosTagHelper.NOUN_V_NAZ_PATTERN, null, Pattern.compile("[a-z].*"), Dir.REVERSE);
      if( v2pos >= 0 && v2pos >= state.verbPos-3 ) {
        if( CaseGovernmentHelper.hasCaseGovernment(tokens[v2pos], PosTagHelper.NOUN_V_NAZ_PATTERN, "v_inf") ) {
//            && CaseGovernmentHelper.hasCaseGovernment(tokens[v2pos], PosTagHelper.NOUN_V_NAZ_PATTERN, "v_dav") ) {

          // exc: бажання вчитися новому
          if( PosTagHelper.hasPosTagPart(tokens[nounAdjPos], "v_dav")
              && LemmaHelper.hasLemma(tokens[verbPos], Pattern.compile(".*вчити(ся)?")) ) {
            return false;
          }
          
          logException();
          return true;

//          if( PosTagHelper.hasPosTagStart(tokens[nounAdjPos], "noun") ) {
//            logException();
//            return true;
//          }
//          if( PosTagHelper.hasPosTagStart(tokens[nounAdjPos], "adj") ) {
//            List adjInflections = InflectionHelper.getAdjInflections(tokens[nounAdjPos].getReadings());
//            List nounInflections = InflectionHelper.getNounInflections(tokens[nounAdjPos].getReadings());
//            if( ! Collections.disjoint(adjInflections, nounInflections) ) {
//              logException();
//              return true;
//            }
//          }
        }
      }
    }
    
    // V:INF + V + N
    // платити доведеться повну вартість
    if( verbPos > 1
        && CaseGovernmentHelper.hasCaseGovernment(state.verbAnalyzedTokenReadings, PosTagHelper.VERB_PATTERN, "v_inf") ) {
      int v2pos = LemmaHelper.tokenSearch(tokens, state.verbPos-1, PosTagHelper.VERB_PATTERN, null, Pattern.compile("[a-z].*"), Dir.REVERSE);
      if( v2pos >= 0 && v2pos >= state.verbPos-3
          && PosTagHelper.hasPosTagPart(tokens[v2pos], ":inf")
          && agrees(tokens[v2pos], state.nounAdjNazInflections, state.nounAdjIndirTokenReadings) 
          ) {
        logException();
        return true;
      }
    }
    
    
    // в мені наростали впевеність і ...
    if( nounAdjPos < tokens.length - 2
        && PosTagHelper.hasPosTag(tokens[verbPos], Pattern.compile("verb.*:p(:.*)?"))
        && PosTagHelper.hasPosTagPart(tokens[nounAdjPos], ":v_naz")
        ) {
      logException();
      return true;
    }

    // змалював дивовижної краси церкву
    if( nounAdjPos < tokens.length - 2
        && PosTagHelper.hasPosTag(tokens[nounAdjPos], Pattern.compile("adj:.:v_rod(?!.*pron).*"))
        && PosTagHelper.hasPosTag(tokens[nounAdjPos+1], Pattern.compile("noun:.*v_rod(?!.*pron).*"))
        && PosTagHelper.hasPosTag(tokens[nounAdjPos+2], Pattern.compile("(noun|adj)(?!.*pron).*")) ) {
      
      List readings = tokens[nounAdjPos+2].getReadings();
      List readingsVnaz = readings.stream().filter(r -> PosTagHelper.hasPosTagPart(r, "v_naz")).collect(Collectors.toList());
      List nounAdjNazInflectionsVnaz = VerbInflectionHelper.getNounInflections(readingsVnaz);
      nounAdjNazInflectionsVnaz.addAll(VerbInflectionHelper.getAdjInflections(readingsVnaz));

      List readingsIndir = readings.stream().filter(r -> ! PosTagHelper.hasPosTagPart(r, "v_naz")).collect(Collectors.toList());
//      List nounAdjInflectionsIndir = InflectionHelper.getNounInflections(readingsIndir);
//      nounAdjInflectionsIndir.addAll(InflectionHelper.getAdjInflections(state.nounAdjIndirTokenReadings));
//      nounAdjInflectionsIndir.addAll(InflectionHelper.getNumrInflections(state.nounAdjIndirTokenReadings));
      
      if( agrees(tokens[verbPos], nounAdjNazInflectionsVnaz, readingsIndir) ) {
        logException();
        return true;
      }
    }
    
    // могли б займатися структури
    // має також народитися власна ідея
    // мали змогу оцінити відвідувачі
    if( verbPos > 2
        && PosTagHelper.hasPosTagPart(tokens[verbPos], ":inf")
        && PosTagHelper.hasPosTagStart(tokens[verbPos-2], "verb")
        && (LemmaHelper.hasLemma(tokens[verbPos-1], Arrays.asList("б","би"))
            || PosTagHelper.hasPosTag(tokens[verbPos-1], Pattern.compile("adv(?!p).*"))
                || LemmaHelper.hasLemma(tokens[verbPos-2], Arrays.asList("мати"), "verb"))
        // && agree 
        ) {
      
      logException();
      return true;
    }
    
    return false;
  }


  private static boolean agrees(AnalyzedTokenReadings verbTokenReadings, List nounAdjNazInflections, List nounAdjIndirTokenReadings) {

    if( nounAdjNazInflections != null && nounAdjNazInflections.size() > 0 ) {
      List verbInflections = VerbInflectionHelper.getVerbInflections(verbTokenReadings.getReadings());
      if (! Collections.disjoint(verbInflections, nounAdjNazInflections))
        return true;
    }

    if( nounAdjIndirTokenReadings.size() > 0 ) {
      Set cases = CaseGovernmentHelper.getCaseGovernments(verbTokenReadings, PosTagHelper.VERB_ADVP_PATTERN);
      if( cases.size() > 0 && TokenAgreementPrepNounRule.hasVidmPosTag(cases, nounAdjIndirTokenReadings) )
        return true;
    }
    return false;
  }

  private static void logException() {
    if( logger.isDebugEnabled() ) {
      StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[2];
      logger.debug("exception: " /*+ stackTraceElement.getFileName()*/ + stackTraceElement.getLineNumber());
    }
  }

  static int isExceptionHardAdjNoun(AnalyzedTokenReadings[] tokens, int i, State state) {

    // понад - very complicated
    // зайнявся понад тисячу справ
//    if( tokens[i].getCleanToken().equals("понад") )
//      continue;

    String cleanTokenLower = tokens[i].getCleanToken().toLowerCase();
    if( cleanTokenLower.matches("[0-9]{4}-.+|нікому|нічому|нічого|нікого|нічим|решту|ніщо") ) {
      return 1;
    }

    if( LemmaHelper.hasLemma(tokens[i], Arrays.asList("сам", "самий", "себе", "один")) ) {
      return 1;
    }

    // висміювати такого роду забобони
    if( i < tokens.length - 1
        && PosTagHelper.hasPosTag(tokens[i], Pattern.compile("adj:m:v_rod.*"))
        && tokens[i+1].getCleanToken().matches("роду|разу|типу|штибу|розміру")
        ) {
      return 1;
    }
    if( i < tokens.length - 1
        && PosTagHelper.hasPosTag(tokens[i], Pattern.compile("(adj|numr):[mp]:v_oru.*"))
        && tokens[i+1].getCleanToken().matches("чином|способом|робом|ходом|шляхом|коштом") ) {
          return 1;
    }
    if( i < tokens.length - 1
        && PosTagHelper.hasPosTag(tokens[i], Pattern.compile("adj:f:v_oru.*"))
        && tokens[i+1].getCleanToken().matches("мірою")
        ) {
      return 1;
    }
    if( i < tokens.length - 1
        && PosTagHelper.hasPosTag(tokens[i], Pattern.compile("adj:f:v_rod.*"))
        && tokens[i+1].getCleanToken().matches("якості|свіжості")
        ) {
      return 1;
    }
    if( i < tokens.length - 1
        && tokens[i+1].getCleanToken().toLowerCase().matches("темпами")
        ) {
      return 1;
    }

    if (new SearchHelper.Match().tokenLine("не те щоб").mNow(tokens, i) == i + 2
        || new SearchHelper.Match().tokenLine("не те що").mNow(tokens, i) == i + 2
        || new SearchHelper.Match().tokenLine("не останньою чергою").mNow(tokens, i) == i + 2)
      return 3;

    if( new SearchHelper.Match().tokenLine("не те, що").mNow(tokens, i) == i + 3 )
      return 4;

    if( new SearchHelper.Match().tokenLine("світ за очі").mNow(tokens, i) == i + 2 )
      return 3;

    if( new SearchHelper.Match().tokenLine("ні світ ні").mNow(tokens, i) == i + 2 )
      return 3;

    if( new SearchHelper.Match().tokenLine("куди очі").mNow(tokens, i) == i + 1 )
      return 3;

    if( new SearchHelper.Match().tokenLine("куди очі").mNow(tokens, i) == i + 1 )
      return 3;

    if( new SearchHelper.Match().tokenLine("станом на").mNow(tokens, i) == i + 1 )
      return 3;

    if( new SearchHelper.Match().tokenLine("страх як").mNow(tokens, i) == i + 1 )
      return 3;

    if( new SearchHelper.Match().tokenLine("жах як").mNow(tokens, i) == i + 1 )
      return 3;

    if( tokens[i-1].getCleanToken().equals("не")
        && tokens[i].getCleanToken().matches("указ|варіант|рідкість")
        ) {
      return 0;
    }

    return -1;
  }

  private static final Pattern PARTS_CANT_SKIP = Pattern.compile("і|й|та|чи|або|але|як|де|куди|наче|ніби|хоч|навіщо|немов|вдвічі|дедалі|щойно|наскільки");
  static int isExceptionSkip(AnalyzedTokenReadings[] tokens, int i) {

    String cleanTokenLower = tokens[i].getCleanToken().toLowerCase();
    
    if( PosTagHelper.hasPosTagAll(tokens[i].getReadings(), Pattern.compile("(part|adv).*"))
       && ! LemmaHelper.ADV_QUANT_PATTERN.matcher(cleanTokenLower).matches()
      && ! PARTS_CANT_SKIP.matcher(cleanTokenLower).matches() ) {
      return 0;
    }
    if( PosTagHelper.hasPosTag(tokens[i].getReadings(), Pattern.compile("part.*"))
       && PosTagHelper.hasPosTagAll(tokens[i].getReadings(), Pattern.compile("(part|conj|adv).*")) 
       && ! PARTS_CANT_SKIP.matcher(cleanTokenLower).matches() ) {
      return 0;
    }

    return -1;
  }

  static RuleException isExceptionVerb(AnalyzedTokenReadings[] tokens, int i, State state) {
    
    if( LemmaHelper.hasLemma(tokens[i], Arrays.asList("мусити")) )
      return new RuleException(Type.exception);
    
    String cleanTokenLower = tokens[i].getCleanToken().toLowerCase();

    if( cleanTokenLower.equals("може") )
      return new RuleException(Type.exception);

    // як є
    if( i > 1 
        && (cleanTokenLower.matches("є") || LemmaHelper.hasLemma(tokens[i], "могти"))
        && tokens[i-1].getCleanToken().equalsIgnoreCase("як")
        ) {
      return new RuleException(Type.exception);
    }
    
    // будь то
    if( i < tokens.length - 2
        && cleanTokenLower.equals("будь")
        && tokens[i+1].getCleanToken().equalsIgnoreCase("то")
        ) {
      return new RuleException(Type.exception);
    }
    
    // вкласти спати Маринку
    if( i > 1 && i < tokens.length - 1
        && tokens[i].getCleanToken().toLowerCase().equals("спати")
        && LemmaHelper.hasLemma(tokens[i-1], Pattern.compile("(по|в)?кла(сти|вши)"))
        ) {
      return new RuleException(Type.skip);
    }
    
    // розпочав був
    if( i > 1 && state != null ) {
      // TODO: merge with unify
      if( cleanTokenLower.matches("був|було")
          && PosTagHelper.hasPosTag(tokens[i-1], Pattern.compile("verb.*:past:m.*")) ) {
        return new RuleException(0);
      }
      if( cleanTokenLower.matches("були|було")
          && PosTagHelper.hasPosTag(tokens[i-1], Pattern.compile("verb.*:past:p.*")) ) { 
        return new RuleException(0); 
      }
      if( cleanTokenLower.equals("було")
          && PosTagHelper.hasPosTag(tokens[i-1], Pattern.compile("verb.*:past:n.*")) ) { 
        return new RuleException(0); 
      }
      if( cleanTokenLower.matches("була|було")
          && PosTagHelper.hasPosTag(tokens[i-1], Pattern.compile("verb.*:past:f.*")) ) { 
        return new RuleException(0); 
      }
    }

    if( i > 1
        && cleanTokenLower.matches("було|буде") ) {
      // чути/проголошено було
      if( state != null 
          && PosTagHelper.hasPosTag(tokens[i-1], Pattern.compile("verb.*(impers|predic).*")) ) {
        return new RuleException(0); 
      }
      // видно/варто було
//      if( LemmaHelper.hasLemma(tokens[i-1], Arrays.asList("видно", "помітно")) // temporary until new dict
//          || PosTagHelper.hasPosTag(tokens[i-1], Pattern.compile(".*predic.*")) ) {
//        return new RuleException(Type.exception); 
//      }
    }

    return new RuleException(Type.none); 
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy