void CRusSentence::BuildDash(int iClauseNum, int iWrdAfter, bool bCopul) { SClauseType type; CClause& pClause = GetClause(iClauseNum); if (bCopul) { pClause.ChangeAllClauseTypesToOneType(SClauseType(COPUL_T, -1,-1)); return; } if ( m_Words[iWrdAfter].IsInOborot() ) return; if (pClause.IsInTermin(iWrdAfter)) return; if (IsBetweenGraphematicalPairDescriptors(iWrdAfter)) return; int DashWordNo = iWrdAfter + 1; m_Words.insert(m_Words.begin() + DashWordNo, CreateDash(this)); RecalculateIndicesAfterInsertingWord(DashWordNo); pClause.ChangeAllClauseTypesToOneType(SClauseType(DASH_T, DashWordNo, 0) ); }
// проверяет, что вершина клаузы iClauseNum1 и вершина iClauseNum2 согласовани как личные глагольные формы bool CRusSentence::CheckCoordinarionBetweenClauseRoots(GrammemCompare CompareFunc, int iClauseNum1, int iClauseNum2 ) const { const CClause& C1 = GetClause(iClauseNum1); const CClause& C2 = GetClause(iClauseNum2); for (int i = 0; i < C1.m_vectorTypes.size(); i++) for (int k = 0; k < C2.m_vectorTypes.size(); k++) if ( !C1.m_vectorTypes[i].m_Root.IsEmpty() && !C2.m_vectorTypes[k].m_Root.IsEmpty() ) { const CSynHomonym& H1 = m_Words[C1.m_vectorTypes[i].m_Root.m_WordNo].m_Homonyms[C1.m_vectorTypes[i].m_Root.m_HomonymNo]; const CSynHomonym& H2 = m_Words[C2.m_vectorTypes[k].m_Root.m_WordNo].m_Homonyms[C2.m_vectorTypes[k].m_Root.m_HomonymNo]; if (GetOpt()->GetGramTab()->Gleiche(CompareFunc, H1.m_GramCodes.c_str(), H2.m_GramCodes.c_str())) return true; }; return false; };
/* Эта функция вызывается только из RuleForEmptyClauses. Проверяет, может ли клауза войти в левостоящую. Если не может, тогда возвращает истину. */ bool CRusSentence::HasStrictBorderLeft(int iClauseNum) { CClause* pAbstClause = &GetClause(iClauseNum); if( HasStrictestLeftClauseBorder(iClauseNum) ) return true; if( iClauseNum == 0) return true; if( pAbstClause->HasLeftStarter() ) return true; return false; }
bool CRusSentence::FindNounFromTheRightOfParticiple(const CClause* pClause, const CSynHomonym& Participle) const { int iType = pClause->FindType(PARTICIPLE_T); assert ( -1 != iType ); // начинаем идти от причастия вправо for(int WordNo = pClause->m_vectorTypes[iType].m_Root.m_WordNo + 1 ; WordNo <= pClause->m_iLastWord ; WordNo++ ) { const CSynWord& pWord = m_Words[WordNo]; // проверка на вложенную клаузу, нужно увеличить индекс WordNo на длину вложенной клаузы int iEncloseCl = GetMinClauseByFirstWord(WordNo); if ( iEncloseCl != -1 ) { assert (GetClause(iEncloseCl).is_inside_of(*pClause)); WordNo = GetClause(iEncloseCl).m_iLastWord; continue; } CSVI Dummy; if ( pClause->IsInThisGroup(WordNo, PREP_NOUN, Dummy) ) continue; for(int j = 0 ; j < pWord.m_Homonyms.size() ; j++ ) { const CSynHomonym& Noun = pWord.m_Homonyms[j]; if( !GetRusGramTab()->IsMorphNoun(Noun.m_iPoses) ) continue; if (CheckCoordinationOfNounAndParticiple(Participle, pClause, WordNo, j)) return true; } } return false; }
bool CRusSentence::RuleForSubClauseWithCoordiantion(int iClauseNum) { const CClause* pAbstClause = &GetClause(iClauseNum); int iWord = pAbstClause->m_iFirstWord; if( pAbstClause->HasType(INP_T) || (pAbstClause->m_vectorTypes.size() == 0) ) return false; // берем следующую клаузу, которая должна быть с сочинительным союзом int iNext = GetMaxClauseByFirstWord(m_Clauses[iClauseNum].m_iLastWord+1); if(iNext == -1) return false; const CClause* pAbstClause1 = &GetClause(iNext); int type = pAbstClause1->FindCommonType(*pAbstClause); switch (type) { case INP_T : case -1 : return false; case PARTICIPLE_T: if (!CheckCoordinarionBetweenClauseRoots(GenderNumberCaseRussian, iClauseNum, iNext)) return false; break; case ADVERB_PARTICIPLE_T: break;// do noting default: if ( ClauseHasSubjPredik(GetClause(iNext)) // если вторая клаузы имеет подлежащее, тогда согласование искать не надо || !CheckCoordinarionBetweenClauseRoots(FiniteFormCoordRussian, iClauseNum, iNext) ) // проверка на неоднозначность границы if(GetMinClauseByLastWord(m_Clauses[iClauseNum].m_iLastWord) != GetMaxClauseByLastWord(m_Clauses[iClauseNum].m_iLastWord)) return false; /* если во вставляемой клаузе вершина омонимична, то мы должны делать следующее: 1. Либо удалить все непрeдикатные омонимы, оставив только прeдикаты, поскольку пустыха не может быть вложена; 2. Либо не обрабатывать эти случаи совсем, поскольку позже с непредикатными омонимами может что-нибудь хорошее произойти Мы предпочитаем второе решение, хотя это фактически использование старого определения пустыхи, что не очень идеологично. Когда-нибудь нужно будет поменять. Сокирко 31.10.02 */ if (!pAbstClause1->HasUnambiguousStrongRootWithoutWeakHomonyms()) return false; break; } if( pAbstClause1->size() < 2 ) return false; int iFirstWord = pAbstClause1->m_iFirstWord; bool bCoordConj = ( (GetWords()[iFirstWord].m_strWord[0] == ',') && m_Words[iFirstWord+1].m_bSimilarConj ) || m_Words[iFirstWord].m_bSimilarConj; if (!bCoordConj) return false; return EncloseClauseAsWord(iNext, iClauseNum); }
bool CRusSentence::RuleForEmptyClauses(int iClauseNum) { const CClause& Clause = GetClause(iClauseNum); int iWord = Clause.m_iFirstWord; if( !IsGoodEmptyClause( &Clause ) ) return false; bool bStrictPrevClauseBorder = HasStrictBorderLeft(iClauseNum); //берем тот фрагмент, который стоит справа от найденной цепочки // если в текущую клаузу была вложена другая клауза, которая заканчивается там же, где текущая клауза // тогда не будем добавлять пустыху направо (неоднозначность границ ), int iNext = GetMaxClauseByFirstWord(m_Clauses[iClauseNum].m_iLastWord+1); CClause* pAbstClauseRight = NULL; if( iNext != -1 ) pAbstClauseRight = &GetClause(iNext); bool bCanConnectRight = pAbstClauseRight && CanBeMainClauseOfTheLeftGoodEmptyClause(pAbstClauseRight, bStrictPrevClauseBorder) && (GetMinClauseByLastWord(Clause.m_iLastWord) == iClauseNum) && !HasStrictBorderLeft(iNext); //берем тот фрагмент, который стоит слева от найденной цепочки CClause* pAbstClauseLeft = NULL; int iPrev = GetMinClauseByLastWord(Clause.m_iFirstWord-1); if( iPrev != -1 ) pAbstClauseLeft = &GetClause(iPrev); // если предыщая клауза была вложена в другую клаузу, тогда не будем добавлять пустыху налево, // поскольку пустыха может войти обе клаузы (в меньшую и в большую"), // например: // "интервью, опубликованное в четверг, 12 апреля" // "12 апреля" надо вкладывать в причастный оборот // "упал кран, который нам подарили японцы, 12 апреля" // "12 апреля" надо вкладывать в главную клаузу // мы имеем здесь абсолютныю неоднозначноть bool bCanConnectLeft = pAbstClauseLeft && !pAbstClauseLeft->HasType(INP_T) && !Clause.HasLeftStarter() && !IsEnclosedClause(iPrev) && !HasStrictestLeftClauseBorder(iClauseNum); // соединение влево будем считать более приоритетным if(bCanConnectLeft) { /* если объединяется пустыха с инфинитивом, тогда тип объединенной клаузы должен быть инфинитовом если объединяется пустыха со сравном, тогда тип объединенной клаузы должен быть СРАВН */ if ( ( Clause.HasType(INFINITIVE_T) || Clause.HasType(COMPARATIVE_T) ) && pAbstClauseLeft->m_vectorTypes.empty() && 1 == pAbstClauseLeft->m_vectorTypes.size() ) UniteClauses(iPrev, iClauseNum, RightClauseParams); else UniteClauses(iPrev, iClauseNum, LeftClauseParams); return true; } if(bCanConnectRight) { UniteClauses(iClauseNum, iNext, RightClauseParams); return true; } return false; }
bool CRusSentence::RuleForParticiples(int iClauseNum) { CClause* pAbstClause = &GetClause(iClauseNum); int iWord = pAbstClause->m_iFirstWord; if ( IsEnclosedClause (iClauseNum) ) return false; if ( pAbstClause->HasUnambiguousStrongRootWithoutWeakHomonyms()) return false; int iParticipleType; if( (iParticipleType = pAbstClause->FindType(PARTICIPLE_T)) == -1 ) return false; assert(!pAbstClause->m_vectorTypes[iParticipleType].m_Root.IsEmpty()); CSynWord& pParticiple = m_Words[pAbstClause->m_vectorTypes[iParticipleType].m_Root.m_WordNo]; int iPart = pParticiple.GetHomonymByPOS(PARTICIPLE); if( iPart == -1 ) return false; //пытаемся найти слева int iPrev = FindNounFromTheLeftOfParticiple(pAbstClause, pParticiple.GetSynHomonym(iPart)); //пытаемся найти слева подходящее сущ.(тогда причастие после определяемого слова) if ( ( m_Words[iWord].m_SubordinateConjNo == -1 ) && ( (pAbstClause->m_iFirstWord != pAbstClause->m_iLastWord ) || ( (iWord+1<m_Words.size()) && (m_Words[iWord+1].m_SubordinateConjNo != -1 ) ) ) && (iPrev != -1) && ( pAbstClause->m_iLastWord+1 == m_Words.size() // проверка правой границы (должен быть знак препинания) || m_Words[pAbstClause->m_iLastWord+1].HasDes(OPun) ) ) { /* Поскольку мы собираемся вкладывать клаузу, нам приходится удалять все вершины клаузы, кроме найденного причастия и все омонимы причастия */ // уничтожаем другие вершины клаузы int k = 0; for( ; k < pAbstClause->m_vectorTypes.size() ; k++) { if(iParticipleType == k) continue; if(k < iParticipleType) iParticipleType--; int WordNo = pAbstClause->m_vectorTypes[k].m_Root.m_WordNo; // не будем удалять омоним, если он единственный у слова if (pAbstClause->GetWords()[WordNo].GetHomonymsCount() > 1) pAbstClause->DeleteHomonym(pAbstClause->m_vectorTypes[k].m_Root.m_WordNo, pAbstClause->m_vectorTypes[k].m_Root.m_HomonymNo); else pAbstClause->DeleteClauseType( k ); k--; } // заново надо найти омоними причастия, поскольку мы в предыдущем цикле удалили некоторые омонимы iPart = pParticiple.GetHomonymByPOS(PARTICIPLE); int PartWordNo = pAbstClause->m_vectorTypes[iParticipleType].m_Root.m_WordNo; // уничтожаем омонимы причастия (прилагательное или существительное), for(k = 0 ; k < pParticiple.GetHomonymsCount() ; k++) { if(iPart == k) continue; if(k < iPart) iPart--; pAbstClause->DeleteHomonym(PartWordNo, k); k--; } return EncloseClauseAsWord(iClauseNum, iPrev); } else // пытаемся найти справа (причастие не отделено запятой) if( FindNounFromTheRightOfParticiple(pAbstClause, pParticiple.GetSynHomonym(iPart) ) ) { // тогда нужно удалить клаузный вариант причастия, а если вариант только один, тогда // нужно его отконвертировать в пустыху if(pAbstClause->m_vectorTypes.size() == 1) { assert (pAbstClause->m_vectorTypes[0].m_Type == PARTICIPLE_T); pAbstClause->ChangeAllClauseTypesToOneType( SClauseType(UnknownSyntaxElement,-1,-1) ); } else { assert( iParticipleType >= 0); pAbstClause->DeleteClauseType( iParticipleType ); } } return false; }
void CRusSentence::TryToRebuildDashInClause() { StringVector v_CopulList; InitCopulList(v_CopulList); for (int ClauseNo = 0; ClauseNo < GetClausesCount(); ClauseNo++) { CClause& pClause = GetClause(ClauseNo); if (!pClause.m_vectorTypes.empty()) continue; bool bHasDash = false; if ( pClause.m_iFirstWord != 0 ) for ( int tt = pClause.m_iFirstWord; tt <= pClause.m_iLastWord; tt++ ) if ( m_Words[tt].m_bDash ) { bHasDash = true; break; } if ( bHasDash ) continue; int j = pClause.m_iFirstWord; for (; j <= pClause.m_iLastWord; j++) if ( !m_Words[j].GetSynHomonym(0).IsLemma("”") && m_Words[j].GetHomonymByPOS(PREP) != -1 ) break; if ( j < pClause.m_iLastWord ) continue; vector<int> Noun_Nom, Adj_Nom, Eto, Noun_Gen, Copul_Words, Noun_NomSgPl; int Prep_U = -1; bool Vozrast = false; for (j = pClause.m_iFirstWord; j <= pClause.m_iLastWord; j++) { if ( m_Words[j].GetSynHomonym(0).IsLemma("Ё“ќ") ) { Eto.push_back(j); continue; } for (int ll = 0; ll < v_CopulList.size(); ll++) if ( m_Words[j].m_strWord == v_CopulList[ll].c_str() ) { Copul_Words.push_back(j); continue; } if ( m_Words[j].GetHomonymsCount() > 1 && !isdigit((BYTE)m_Words[j].m_strWord[0]) ) continue; if ( m_Words[j].GetSynHomonym(0).IsLemma(" ќ“ќ–џ…") ) continue; if ( HasNounInNom( m_Words[j]) && !m_Words[j].HasDes(OFAM2) ) { Noun_Nom.push_back(j); continue; } if ( HasAdjInNom(m_Words[j]) && !m_Words[j].HasDes(OFAM2) ) { Adj_Nom.push_back(j); continue; } if ( m_Words[j].GetSynHomonym(0).IsLemma("”") ) { Prep_U = j; continue; } if ( HasNounInGen(m_Words[j]) ) Noun_Gen.push_back(j); if ( HasNounInNomSgPl( m_Words[j] ) ) Noun_NomSgPl.push_back(j); if (0 == Adj_Nom.size() && 0 == Noun_Nom.size() && isdigit((BYTE)m_Words[j].m_strWord[0]) // ≈му 33. && m_Words[j].m_strWord.find("-") == string::npos && j >= m_Words.size()-2 && !m_Words[m_Words.size()-1].m_Homonyms[0].m_bMonth && !m_Words[m_Words.size()-2].m_Homonyms[0].m_bMonth) { Vozrast = true; Adj_Nom.push_back(j); continue; } } if (0 == Noun_Nom.size() && 0 == Eto.size() && 0 == Adj_Nom.size() && -1 == Prep_U) continue; if ( Vozrast && 0 < Noun_Nom.size() && m_Words[Noun_Nom[0]].m_strUpperWord == "√ќƒ" && 0 == Eto.size() && 1 == Adj_Nom.size() && -1 == Prep_U) //ему 21 год Noun_Nom.clear(); if (0 == Noun_Nom.size() && 0 == Eto.size() && 1 == Adj_Nom.size() && -1 == Prep_U) // √лаза красивые. for (j = pClause.m_iFirstWord; j <= pClause.m_iLastWord; j++) { m_Words[j].SetHomonymsDel(true); for (int i = 0; i < m_Words[j].m_Homonyms.size() && 0 == Noun_Nom.size(); i++) { if ( m_Words[j].m_Homonyms[i].IsSynNoun() ) { if ( (m_Words[j].m_Homonyms[i].HasGrammem(rNominativ) && (m_Words[j].m_Homonyms[i].m_iGrammems & rAllNumbers & m_Words[Adj_Nom[0]].GetGrammems()) && (m_Words[j].m_Homonyms[i].HasGrammem(rPlural) // согласуем род если ед.ч. || (m_Words[j].m_Homonyms[i].m_iGrammems & rAllGenders & m_Words[Adj_Nom[0]].GetGrammems()))) || (Vozrast && m_Words[j].m_Homonyms[i].HasGrammem(rDativ) )) // ≈му 33. { m_Words[j].m_Homonyms[i].m_bDelete = false; Noun_Nom.push_back(j); } } } if (Noun_Nom.size() > 0 && find(Noun_Nom.begin(), Noun_Nom.end(), j) != Noun_Nom.end()) m_Words[j].DeleteMarkedHomonymsBeforeClauses(); else m_Words[j].SetHomonymsDel(false); } else Vozrast = false; if (Noun_Nom.size() > 1) { BYTE up_let = m_Words[Noun_Nom[1]].m_strWord[0]; if (!is_russian_upper(up_let)) { int k = 0; for (; k < Copul_Words.size(); k++) if (Copul_Words[k] > Noun_Nom[0] && Copul_Words[k] < Noun_Nom[1]) { BuildDash(ClauseNo, -1, true); break; } if ( k == Copul_Words.size()) BuildDash(ClauseNo, Noun_Nom[0]); } continue; } if ( Noun_Nom.size() > 0 && Eto.size() > 0 ) { QWORD tormoz = _QM(rNeutrum) | _QM(rSingular) | _QM(rNominativ); for (int k = 0; k < Eto.size() && k < Noun_Nom.size(); k++) // без "тормоза" во фразе "это облако" восстановитс¤ тире if (!m_Words[Noun_Nom[k]].GetSynHomonym(0).HasSetOfGrammemsExact(tormoz) ) if (Noun_Nom[k] > Eto[k]) { BuildDash(ClauseNo, Eto[k]); continue; } } bool bPersCl, bEncCl; bPersCl = bEncCl = false; int cc = ClauseNo-1; for (; ClauseNo > 1 && cc >= 0; cc--) { CClause& pClauseBefore = GetClause(cc); if ( pClauseBefore.HasType(VERB_PERS_T) && pClauseBefore.HasLeftStarter() ) { bEncCl = true; continue; } if ( pClauseBefore.HasType(PARTICIPLE_T) || pClauseBefore.HasType(ADVERB_PARTICIPLE_T) ) { bEncCl = true; continue; } if ( pClauseBefore.HasType(DASH_T) ) break; if ( ( !pClauseBefore.HasType(INFINITIVE_T) && !pClauseBefore.m_vectorTypes.empty() ) || !(pClauseBefore.m_vectorTypes.size() == 1) ) { if (bEncCl) bPersCl = true; break; } } if (bPersCl) continue; bPersCl = bEncCl = false; for (cc = ClauseNo+1; ClauseNo < GetClausesCount()-2 && cc < GetClausesCount(); cc++) { CClause& pClauseAfter = GetClause(cc); if ( pClauseAfter.HasType(VERB_PERS_T) && pClauseAfter.HasLeftStarter() ) { bEncCl = true; continue; } if ( pClauseAfter.HasType(PARTICIPLE_T) || pClauseAfter.HasType(ADVERB_PARTICIPLE_T) ) { bEncCl = true; continue; } if ( pClauseAfter.HasType(DASH_T) ) break; if ( ( !pClauseAfter.HasType(INFINITIVE_T) && !pClauseAfter.m_vectorTypes.empty() ) || !(pClauseAfter.m_vectorTypes.size() == 1) ) { if (bEncCl) bPersCl = true; break; } } if (bPersCl) continue; if ( Noun_Nom.size() > 0 && Adj_Nom.size() > 0 ) { for (int k = 0; k < Noun_Nom.size() && k < Adj_Nom.size(); k++) if ( Noun_Nom[k] < Adj_Nom[k] && (pClause.m_iLastWord == Adj_Nom[k] || !HasGenderNumberCaseNP(m_Words[Adj_Nom[k]], m_Words[Adj_Nom[k]+1]) || Vozrast) //≈му 33 года ) { if(Vozrast) for (int h = 0; h < m_Words[Adj_Nom[k]].GetHomonymsCount(); h++) if(m_Words[Adj_Nom[k]].GetHomonym(h)->HasPos(NUMERAL)) m_Words[Adj_Nom[k]].GetHomonym(h)->ModifyGrammems( _QM(rPlural) | _QM(rNominativ) | _QM(rAccusativ)); else m_Words[Adj_Nom[k]].EraseHomonym(h); BuildDash(ClauseNo, Noun_Nom[k]); } continue; } if (-1 != Prep_U && Noun_Gen.size() > 0 && ( Noun_Nom.size() > 0 || Noun_NomSgPl.size() > 0 ) ) { for (int m = 0; m < Noun_Gen.size(); m++) if (Prep_U < Noun_Gen[m]) { Prep_U = Noun_Gen[m]; break; } if ( Noun_Nom.size() > 0 ) { if ( Prep_U > Noun_Nom[0] ) BuildDash(ClauseNo, Noun_Nom[0]); else BuildDash(ClauseNo, Prep_U); continue; } int iNomSgPl = -1; for ( int tt = 0; tt < Noun_NomSgPl.size(); tt++ ) if ( Prep_U != Noun_NomSgPl[tt] ) { iNomSgPl = Noun_NomSgPl[tt]; break; } if ( -1 != iNomSgPl ) if ( Prep_U > iNomSgPl ) BuildDash(ClauseNo, iNomSgPl); else BuildDash(ClauseNo, Prep_U); } } }