Exemple #1
0
// Генерация слов, фонетически близких к заданному word.
// Возвращается список вариантов, включая исходное слово, и список их достоверностей.
void LexicalAutomat::ProducePhonInv(
    const lem::UCString &word,
    int id_language,
    lem::MCollect<lem::UCString> &res,
    lem::MCollect<lem::Real1> &rels,
    LA_RecognitionTrace *trace
)
{
    MCollect<LA_AA_list*> packs;
    LA_AA_list *list = new LA_AA_list;
    list->reserve(16);
    list->push_back(LA_AA_item(word, Real1(100)));

    // Теперь мутированные варианты.
    LA_Pack *pack = AlephAuto(id_language, word, 1, trace);

    for (Container::size_type j = 0; j < pack->size(); j++)
    {
        const Solarix::Lexem &ph_lex = *(pack->get(j));
        if (res.find(ph_lex) == UNKNOWN)
        {
            Real1 r = pack->get(j)->get_Val();
            rels.push_back(r);
            res.push_back(ph_lex);
        }
    }

    return;
}
void LemmatizatorStorage_SQLITE::Lemmatize(
                                           const lem::UCString &word,
                                           lem::MCollect<lem::UCString> &lemmas
                                          )
{
 lemmas.clear();

 lem::MemFormatter mem;
 mem.printf( "SELECT L.lemma"
             " FROM lexemes_n X, lemmas L"
             " WHERE X.lexeme='%us' AND L.id=X.id_lemma", to_upper(word).c_str() );

 lem::Ptr<LS_ResultSet> rs(cnx->Select(lem::to_utf8(mem.string())));
 while( rs->Fetch() )
  {
   lemmas.push_back( rs->GetUCString(0) );
  }

 if( lemmas.empty() )
  {
   lemmas.push_back(word);
  }

 return;
}
bool LA_PreprocessorRules::Crop(
    const lem::UCString &word,
    lem::MCollect<lem::UCString> &results,
    lem::MCollect<lem::Real1> &rels,
    LA_RecognitionTrace *trace
) const
{
    bool applied = false;

    if (!crop_rules.empty())
    {
        // сначала применяем префиксные правила
        typedef CROP_RULES::const_iterator IT;

        LA_CropRule::HashType prefix_hash = LA_CropRule::CalcHash(word.c_str(), true, false);
        std::pair<IT, IT> pp = prefix_crop_rules.equal_range(prefix_hash);

        lem::UCString result;

        for (auto it = pp.first; it != pp.second; ++it)
        {
            const LA_CropRule *r = it->second;
            if (r->Apply(word, result))
            {
                applied = true;
                results.push_back(result);
                rels.push_back(r->GetRel());
                if (trace != nullptr)
                {
                    trace->CropRuleApplied(word, result, r);
                }
            }
        }

        // теперь отсекаем аффикс

        LA_CropRule::HashType affix_hash = LA_CropRule::CalcHash(word.c_str(), false, true);
        pp = affix_crop_rules.equal_range(affix_hash);

        for (auto it = pp.first; it != pp.second; ++it)
        {
            const LA_CropRule *r = it->second;
            if (r->Apply(word, result))
            {
                applied = true;
                results.push_back(result);
                rels.push_back(r->GetRel());
                if (trace != nullptr)
                {
                    trace->CropRuleApplied(word, result, r);
                }
            }
        }
    }

    return applied;
}
void LEMM_Compiler::LoadNGram( lem::Iridium::Macro_Parser & txtfile, Dictionary & dict, lem::MCollect<int> & terms, int order ) const
{
 lem::Iridium::BSourceState beg = txtfile.tellp();

 while( !txtfile.eof() )
 {
  lem::Iridium::BethToken t = txtfile.read();
  if( lem::is_int(t.string()) )
   terms.push_back( lem::to_int(t.string()) );
  else
   {
    txtfile.seekp(t);
    break;
   }
 }

 if( terms.size() != order+1 )
  {
   dict.GetIO().merr().printf( "%vfDInvalid ngram%vn\n" );
   lem::Iridium::Print_Error( beg, txtfile );
   throw lem::E_ParserError();
  }

 return;
}
Exemple #5
0
void Lemmatizator::Lemmatize( const lem::MCollect<lem::UCString> & words, lem::MCollect<lem::UCString> &lemmas )
{
 #if defined LEM_THREADS
 lem::Process::CritSecLocker lock(&cs);
 #endif

 if( !model_loaded )
  {
   bin->seekp( model_pos );
   model_loaded = true;
   model_available = bin->read_bool();
   if( model_available )
    {
     LoadModel();
    }
  }


 if( model_available )
  {
   LemmatizeViaModel( words, lemmas );
  }
 else
  {
   for( lem::Container::size_type i=0; i<words.size(); ++i )
    {
     lem::UCString lemma;
     Lemmatize( words[i], lemma );
     lemmas.push_back( lemma );
    }
  }

 return;
}
void LexerTextPos::Collect_Right2Left(int count, lem::MCollect<const LexerTextPos*> & inverted_path) const
{
    inverted_path.push_back(this);
    if (count > 0 && !IsBegin() && previous != nullptr)
        GetPrev()->Collect_Right2Left(count - 1, inverted_path);

    return;
}
void SynPatternResult::GetExportCoordPairs(lem::MCollect< std::pair<int, int> > & pairs) const
{
    for (auto it = exported_coords.begin(); it != exported_coords.end(); ++it)
    {
        pairs.push_back(*it);
    }

    return;
}
Exemple #8
0
void GeneratorLexer::CollectUsedWords( const LexerTextPos * t, lem::MCollect<int> & indeces ) const
{
 TOKEN2WORD::const_iterator it = token2word.find(t);
 if( it!=token2word.end() )
  indeces.push_back( it->second );

 if( !t->IsBegin() && t->GetPrev()!=NULL )
  CollectUsedWords( t->GetPrev(), indeces );

 return;
}
void LexerTextPos::CollectPathToLeft(int count, lem::MCollect<const Word_Form*> & org) const
{
    LEM_CHECKIT_Z(count >= 0);

    org.push_back(wordform);

    if (count > 0 && previous != NULL)
        previous->CollectPathToLeft(count - 1, org);

    return;
}
Exemple #10
0
void LexerTextPos::Collect_Right2Left(const LexerTextPos *left_boundary, lem::MCollect<const LexerTextPos*> & inverted_path) const
{
    LEM_CHECKIT_Z(left_boundary != nullptr);

    inverted_path.push_back(this);

    if (this != left_boundary && previous != nullptr)
        previous->Collect_Right2Left(left_boundary, inverted_path);

    return;
}
Exemple #11
0
void SynPatterns::GetUnresolvedForwardDeclarations( lem::MCollect<lem::UCString> & unresolved_names ) const
{
 typedef std::map< lem::UCString, int >::const_iterator IT;
 for( IT it=name2id.begin(); it!=name2id.end(); ++it )
  {
   if( id2count.find( it->second )==id2count.end() )
    unresolved_names.push_back( it->first );
  }

 return;
}
void SyllabContext::GetResultSyllabs(lem::MCollect<lem::UCString> & result_syllabs, bool Normalized) const
{
    for (auto point : points)
    {
        if (point->IsLeftBoundary() || point->IsRightBoundary())
            continue;

        result_syllabs.push_back(point->BuildSyllab(Normalized));
    }

    return;
}
Exemple #13
0
void SyllabContext::GetResultSyllabs( lem::MCollect<lem::UCString> & result_syllabs, bool Normalized ) const
{
 for( lem::Container::size_type i=0; i<points.size(); ++i )
  {
   const SyllabContextPoint * p = points[i];
   if( p->IsLeftBoundary() || p->IsRightBoundary() )
    continue;
   
   result_syllabs.push_back( p->BuildSyllab(Normalized) );
  }

 return;
}
// *************************************************************************************
// Ищем парадигмы, чьи условия подходят для указанной базовой формы, возвращает
// список id таких парадигм.
// *************************************************************************************
void ParadigmaFinder::Find( int PartOfSpeech, const lem::UCString &entry_name, lem::MCollect<int> &found_ids )
{
 #if defined LEM_THREADS
 lem::Process::RWU_ReaderGuard rlock(cs);
 #endif

 if( !loaded )
  {
   #if defined LEM_THREADS
   lem::Process::RWU_WriterGuard wlock(rlock);
   #endif
   LoadFromDB();
  }

 if( PartOfSpeech==UNKNOWN || PartOfSpeech==ANY_STATE )
  {
   for( lem::Container::size_type i=0; i<matchers.size(); ++i )
    if( matchers[i]->Match(entry_name) )
     {
      found_ids.push_back(ids[i]);
     }
  }
 else
  {
   CLASS2DECL::const_iterator it=class2decl.find(PartOfSpeech);
   if( it!=class2decl.end() )
    {
     for( lem::Container::size_type i=0; i<it->second->size(); ++i )
      if( it->second->get(i).second->Match(entry_name) )
       {
        found_ids.push_back( it->second->get(i).first );
       }
    }
  }
 
 return;
}
Exemple #15
0
void BasicModel::PullFeatures2( lem::MCollect<lem::CString> & b, const lem::PtrCollect<ModelTokenFeatures> & token_features, int ifocus, int offset1, int offset2 ) const
{
 int iword1 = ifocus + offset1;
 int iword2 = ifocus + offset2;

 if( iword1 >= 0 && iword1 < token_features.size() && iword2 >= 0 && iword2 < token_features.size() )
 {
  b.push_back( lem::format_str( "sfx[%d,%d]=%d,%d", offset1, offset2, token_features[iword1]->suffix_id, token_features[iword2]->suffix_id ).c_str() );

  // здесь можно вывести и другие свойства слов.
  // ... TODO
 }

 return;
}
Exemple #16
0
void BackTraceItem::GetCoordStates( int id_coord, lem::MCollect<int> & states ) const
{
 if( use_export )
  {
   for( lem::Container::size_type i=0; i<export_coords.size(); ++i )
    {
     if( export_coords[i].GetCoord().GetIndex()==id_coord )
      states.push_back( export_coords[i].GetState() );
    }
  }
 else
  {
   states = GetWordform()->GetStates( Solarix::GramCoordAdr(id_coord) );
  }

 return;
}
void NGramsStorage_SQLITE::SelectInts( const lem::FString &Select, lem::MCollect<int> &list )
{
 LEM_CHECKIT_Z( !Select.empty() );

 sqlite3_stmt *stmt=NULL;
 int res = sqlite3_prepare_v2( hdb, Select.c_str(), -1, &stmt, NULL );
 if( res==SQLITE_OK )
  {
   while( sqlite3_step( stmt ) == SQLITE_ROW )
    {
     int i = sqlite3_column_int(stmt,0);
     list.push_back(i);
    } 

   sqlite3_finalize(stmt);
  }

 return;
}
Exemple #18
0
void SG_DeclensionTable::GenerateForms(
                                       const Lexem &entry_name,
                                       lem::MCollect<Lexem> & res,
                                       lem::PtrCollect<CP_Array> & form_dims, 
                                       const SynGram &sg,
                                       const SG_DeclensionAutomat &dsa 
                                      ) const
{
 res.reserve(form.size());

 for( lem::Container::size_type i=0; i<form.size(); i++ )
  {
   UCString frm( dsa.ProduceForm( entry_name, GetClass(), *form[i], sg ) );

   res.push_back( frm);
   form_dims.push_back( new CP_Array( form[i]->GetDim() ) );
  }

 return;
}
Exemple #19
0
void SG_DeclensionTable::GenerateForms(
                                       const Lexem &entry_name,
                                       lem::MCollect<Lexem> &res,
                                       const SynGram &sg,
                                       const SG_DeclensionAutomat &dsa 
                                      ) const
{
 res.reserve(form.size());

 for( lem::Container::size_type i=0; i<form.size(); i++ )
  {
   UCString frm( dsa.ProduceForm( entry_name, GetClass(), *form[i], sg ) );

   // Без повторов
   if( std::find( res.begin(), res.end(), frm )==res.end() )
    res.push_back( frm );
  }

 return;
}
void SynPatternResult::SelectUnique_WithRemoval(lem::MCollect<SynPatternResult*> & results)
{
    lem::MCollect<int> result_hash;
    lem::PtrCollect<SynPatternResult> unique_result;
    for (lem::Container::size_type k = 0; k < results.size(); ++k)
    {
        SynPatternResult * result_k = results[k];
        const int h = result_k->CalcHash();

        bool found = false;
        for (lem::Container::size_type i = 0; i < unique_result.size(); ++i)
        {
            if (result_hash[i] == h)
            {
                if (SynPatternResult::Equals(result_k, unique_result[i]))
                {
                    found = true;
                    break;
                }
            }
        }

        if (!found)
        {
            result_hash.push_back(h);
            unique_result.push_back(result_k);
            results[k] = nullptr;
        }
    }

    results.clear();

    for (lem::Container::size_type i = 0; i < unique_result.size(); ++i)
    {
        results.push_back(unique_result[i]);
        unique_result[i] = nullptr;
    }

    return;
}
Exemple #21
0
static bool IsHtmlClosed( const lem::UFString &tag )
{
 if( tags1.empty() )
  {
   const wchar_t* stags[] = { L"br", L"hr", L"link", L"meta", L"img", L"input",
                              NULL
                            };

   int i=0;
   while(stags[i]!=NULL)
    tags1.push_back( lem::UFString(stags[i++]) );
  }

 for( lem::Container::size_type i=0; i<tags1.size(); ++i )
  {
   const lem::UFString &t = tags1[i];
   if( tag.eq_begi(t) && (tag.length()==t.length() || tag[ t.length() ]==L' ' ) ) 
    return true;
  }

 return false;
}
Exemple #22
0
static bool IsTextDelimiterTag( const UFString &tag )
{
 if( tags2.empty() )
  {
   const wchar_t* stags[] = { L"p", L"br", L"table", L"td", L"tr", L"th",
                              L"ol", L"ul", L"li", L"dd", L"input", L"frame", L"div",
                              NULL
                            };

   int i=0;
   while(stags[i]!=NULL)
    tags2.push_back( lem::UFString(stags[i++]) );
  }

 for( lem::Container::size_type i=0; i<tags2.size(); ++i )
  {
   const lem::UFString &t = tags2[i];
   if( tag.eq_begi(t) && (tag.length()==t.length() || tag[ t.length() ]==L' ' ) ) 
    return true;
  }

 return false;
}
Exemple #23
0
void BasicModel::PullFeatures1(
                               lem::MCollect<lem::CString> & b,
                               const lem::PtrCollect<ModelTokenFeatures> & token_features,
                               int ifocus,
                               int offset,
                               bool rich_set,
                               bool emit_Aa_feature
                              ) const
{
 int iword = ifocus + offset;

 if( iword >= 0 && iword < token_features.size() )
 {
  const ModelTokenFeatures & f = * token_features[iword];

  b.push_back( lem::format_str( "sfx[%d]=%d", offset, f.suffix_id ).c_str() );

  if( emit_Aa_feature )
   b.push_back( lem::format_str( "Aa[%d]=%d", offset, f.Aa ).c_str() );

  // здесь можно вывести и другие свойства слова.
  if( rich_set )
  {
   b.push_back( lem::format_str("pos[%d,N]=%s", offset, f.POS_N.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,A]=%s", offset, f.POS_A.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,V]=%s", offset, f.POS_V.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,IMV]=%s", offset, f.POS_IMV.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,I]=%s", offset, f.POS_I.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,Y]=%s", offset, f.POS_Y.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,VY]=%s", offset, f.POS_VY.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PRN]=%s", offset, f.POS_PRN.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PRN2]=%s", offset, f.POS_PRN2.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,C]=%s", offset, f.POS_C.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,D]=%s", offset, f.POS_D.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,P]=%s", offset, f.POS_P.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PX]=%s", offset, f.POS_PX.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PP]=%s", offset, f.POS_PP.c_str() ).c_str() );
  }
 }

 return;
}
Exemple #24
0
void Lemmatizator::LemmatizeViaModel( const lem::MCollect<lem::UCString> & words, lem::MCollect<lem::UCString> &lemmas )
{
 // Для каждого слова получим списки альтернативных лемматизаций.
 lem::Collect< lem::MCollect<lem::UCString> > word2lemmas;
 word2lemmas.resize( words.size() );

 lem::MCollect<int> lemma_scores;
 lem::MCollect<int> lemma_order;

 for( lem::Container::size_type i=0; i<words.size(); ++i )
  {
   Lemmatize( words[i], word2lemmas[i] );

   for( lem::Container::size_type j=0; j<word2lemmas[i].size(); ++j )
    word2lemmas[i][j].to_lower();

   lemmas.push_back( word2lemmas[i][0] );
   lemma_scores.push_back(0);
   lemma_order.push_back(1);
  }


 const int last_word_index = CastSizeToInt(words.size())-1;

 const bool use_4grams=true;
 const bool use_3grams=true;
 const bool use_2grams=true;

 for( lem::Container::size_type iword = 0; iword < words.size(); ++iword )
  {
   lem::UCString lemma;
   int lemma_score = 0;
   bool lemma_created = false;

   if( !lemma_created && iword > 2 && use_4grams )
    {
     // ======================
     // ИСПОЛЬЗУЕМ ТЕТРАГРАММЫ
     // ======================

     const lem::UCString & word1 = words[iword-3];
     const int id_suffix1 = GetTag( word1 );

     const lem::UCString & word2 = words[iword-2];
     const int id_suffix2 = GetTag( word2 );

     const lem::UCString & word3 = words[iword-1];
     const int id_suffix3 = GetTag( word3 );

     lem::triple<int,int,int> k3( id_suffix1, id_suffix2, id_suffix3 );

     std::map< lem::triple<int,int,int>, lem::MCollect<const LEMM_Ngram4*>* >::const_iterator it = tag0_2_ngram4.find( k3 );
     if( it!=tag0_2_ngram4.end() )
      {
       const lem::MCollect<const LEMM_Ngram4*> & n4_list = * it->second;

       std::map<lem::UCString,int> sfx2score;

       int proj_count = word2lemmas[iword].size();
       for( int iproj = 0; iproj < proj_count; ++iproj )
        {
         const lem::UCString & entry_name = word2lemmas[iword][iproj];
         lem::UCString i_sfx = GetSuffix( entry_name );
         if( sfx2score.find( i_sfx )==sfx2score.end() )
          sfx2score.insert( std::make_pair( i_sfx, 0 ) );
        }

       for( lem::Container::size_type j=0; j<n4_list.size(); ++j )
        {
         const LEMM_Ngram4 & n4_probe = *n4_list[j];
         const int id_suffix4 = n4_probe.tags.fourth;
         const lem::UCString & suffix4 = GetSuffixById(id_suffix4);

         std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix4);
         if( it2!=sfx2score.end() )
          it2->second += n4_probe.freq;
        }

       // теперь надо выбрать самый достоверный вариант.
       int best_score = 0;

       lem::UCString prev_lemma;
       int prev_score = 0;

       // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
       for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj )
        {
         const lem::UCString & ename = word2lemmas[iword][iproj];
         lem::UCString proj_suffix = GetSuffix( ename );
         std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix);
         if( it3!=sfx2score.end() )
          {
           const int new_score = it3->second;
           if( new_score > best_score )
            {
             prev_score = new_score;
             prev_lemma = ename;
            }
          }
        }

       // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его.
       if( lemma_scores[iword] < prev_score )
        {
         lemma_scores[iword] = prev_score;
         lemmas[iword] = prev_lemma;
         lemma_order[iword] = 4;
        }
      }
    }



   if( !lemma_created && use_3grams )
    {
     // ======================
     // ИСПОЛЬЗУЕМ ТРИГРАММЫ
     // ======================

     // Если текущее слово имеет 1 вариант лемматизации, то можно использовать его для перепроверки предыдущего слова.

     if( iword>2 && word2lemmas[iword].size() == 1 && word2lemmas[iword - 1].size() == 1 && word2lemmas[iword - 2].size() > 1 && lemma_order[iword-2]<3 )
     {
      // переоцениваем слово в iword-2
      const lem::UCString & word1 = words[iword-1];
      const int id_suffix1 = GetTag( word1 );

      const lem::UCString & word2 = words[iword];
      const int id_suffix2 = GetTag( word2 );

      std::pair<int,int> k2( id_suffix1, id_suffix2 );

      std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag2_2_ngram3.find( k2 );
      if( it!=tag2_2_ngram3.end() )
       {
        const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second;

        std::map<lem::UCString,int> sfx2score;

        int proj_count = word2lemmas[iword-2].size();
        for( int iproj = 0; iproj < proj_count; ++iproj )
         {
          const lem::UCString & entry_name = word2lemmas[iword-2][iproj];
          lem::UCString i_sfx = GetSuffix( entry_name );
          if( sfx2score.find( i_sfx )==sfx2score.end() )
           sfx2score.insert( std::make_pair( i_sfx, 0 ) );
         }

        for( lem::Container::size_type j=0; j<n3_list.size(); ++j )
         {
          const LEMM_Ngram3 & n3_probe = *n3_list[j];
          const int id_suffix0 = n3_probe.tags.first;
          const lem::UCString & suffix0 = GetSuffixById(id_suffix0);

          std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix0);
          if( it2!=sfx2score.end() )
           it2->second += n3_probe.freq;
         }

        // теперь надо выбрать самый достоверный вариант.
        int best_score = 0;

        lem::UCString prev_lemma;
        int prev_score = 0;

        // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
        for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj )
         {
          const lem::UCString & ename = word2lemmas[iword-2][iproj];
          lem::UCString proj_suffix = GetSuffix( ename );
          std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix);
          if( it3!=sfx2score.end() )
           {
            const int new_score = it3->second;
            if( new_score > best_score )
             {
              prev_score = new_score;
              prev_lemma = ename;
             }
           }
         }

        // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его.
        if( lemma_scores[iword-2] < prev_score )
         {
          lemma_scores[iword-2] = prev_score;
          lemmas[iword-2] = prev_lemma;
          lemma_order[iword-2] = 3;
         }
       }
     }
     else if( iword>1 && word2lemmas[iword].size() == 1 && word2lemmas[iword - 1].size() > 1 && lemma_order[iword-1]<3 )
     {
      // переоцениваем слово в iword-1
      const lem::UCString & word0 = words[iword-2];
      const int id_suffix0 = GetTag( word0 );

      const lem::UCString & word2 = words[iword];
      const int id_suffix2 = GetTag( word2 );

      std::pair<int,int> k2( id_suffix0, id_suffix2 );

      std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag1_2_ngram3.find( k2 );
      if( it!=tag1_2_ngram3.end() )
       {
        const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second;

        std::map<lem::UCString,int> sfx2score;

        int proj_count = word2lemmas[iword-1].size();
        for( int iproj = 0; iproj < proj_count; ++iproj )
         {
          const lem::UCString & entry_name = word2lemmas[iword-1][iproj];
          lem::UCString i_sfx = GetSuffix( entry_name );
          if( sfx2score.find( i_sfx )==sfx2score.end() )
           sfx2score.insert( std::make_pair( i_sfx, 0 ) );
         }

        for( lem::Container::size_type j=0; j<n3_list.size(); ++j )
         {
          const LEMM_Ngram3 & n3_probe = *n3_list[j];
          const int id_suffix1 = n3_probe.tags.second;
          const lem::UCString & suffix1 = GetSuffixById(id_suffix1);

          std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1);
          if( it2!=sfx2score.end() )
           it2->second += n3_probe.freq;
         }

        // теперь надо выбрать самый достоверный вариант.
        int best_score = 0;

        lem::UCString prev_lemma;
        int prev_score = 0;

        // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
        for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj )
         {
          const lem::UCString & ename = word2lemmas[iword-2][iproj];
          lem::UCString proj_suffix = GetSuffix( ename );
          std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix);
          if( it3!=sfx2score.end() )
           {
            const int new_score = it3->second;
            if( new_score > best_score )
             {
              prev_score = new_score;
              prev_lemma = ename;
             }
           }
         }

        // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его.
        if( lemma_scores[iword-1] < prev_score )
         {
          lemma_scores[iword-1] = prev_score;
          lemmas[iword-1] = prev_lemma;
          lemma_order[iword-1] = 3;
         }
       }
     }
     else if( word2lemmas[iword].size() > 1 )
     {
      std::map<lem::UCString,int> sfx2score;
      bool needs_resort=false;

      if( iword>1 )
       {
        // iword-2,iword-1 --> iword

        const lem::UCString & word1 = words[iword-2];
        const int id_suffix1 = GetTag( word1 );
      
        const lem::UCString & word2 = words[iword-1];
        const int id_suffix2 = GetTag( word2 );
      
        std::pair<int,int> k2( id_suffix1, id_suffix2 );
      
        std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag0_2_ngram3.find( k2 );
        if( it!=tag0_2_ngram3.end() )
         {
          const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second;
      
          needs_resort=true;
      
          int proj_count = word2lemmas[iword].size();
          for( int iproj = 0; iproj < proj_count; ++iproj )
           {
            const lem::UCString & entry_name = word2lemmas[iword][iproj];
            lem::UCString i_sfx = GetSuffix( entry_name );
            if( sfx2score.find( i_sfx )==sfx2score.end() )
             sfx2score.insert( std::make_pair( i_sfx, 0 ) );
           }
      
          for( lem::Container::size_type j=0; j<n3_list.size(); ++j )
           {
            const LEMM_Ngram3 & n3_probe = *n3_list[j];
            const int id_suffix3 = n3_probe.tags.third;
            const lem::UCString & suffix3 = GetSuffixById(id_suffix3);
      
            std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix3);
            if( it2!=sfx2score.end() )
             it2->second += n3_probe.freq;
           }
         }
       }


      if( iword>0 && iword<last_word_index )
       {
        // iword-1 --> iword <-- iword+1
    
        const lem::UCString & word0 = words[iword-1];
        const int id_suffix0 = GetTag( word0 );
    
        const lem::UCString & word2 = words[iword+1];
        const int id_suffix2 = GetTag( word2 );
    
        std::pair<int,int> k2( id_suffix0, id_suffix2 );
    
        std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag1_2_ngram3.find( k2 );
        if( it!=tag1_2_ngram3.end() )
         {
          const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second;
    
          needs_resort=true;
    
          int proj_count = word2lemmas[iword].size();
          for( int iproj = 0; iproj < proj_count; ++iproj )
           {
            const lem::UCString & entry_name = word2lemmas[iword][iproj];
            lem::UCString i_sfx = GetSuffix( entry_name );
            if( sfx2score.find( i_sfx )==sfx2score.end() )
             sfx2score.insert( std::make_pair( i_sfx, 0 ) );
           }
    
          for( lem::Container::size_type j=0; j<n3_list.size(); ++j )
           {
            const LEMM_Ngram3 & n3_probe = *n3_list[j];
            const int id_suffix1 = n3_probe.tags.second;
            const lem::UCString & suffix1 = GetSuffixById(id_suffix1);
    
            std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1);
            if( it2!=sfx2score.end() )
             it2->second += n3_probe.freq;
           }
         }
       }

      if( iword<last_word_index-1 )
       {
        // iword <-- iword+1,iword+2

        const lem::UCString & word1 = words[iword+1];
        const int id_suffix1 = GetTag( word1 );

        const lem::UCString & word2 = words[iword+2];
        const int id_suffix2 = GetTag( word2 );
      
        std::pair<int,int> k2( id_suffix1, id_suffix2 );
      
        std::map< std::pair<int,int>, lem::MCollect<const LEMM_Ngram3*>* >::const_iterator it = tag2_2_ngram3.find( k2 );
        if( it!=tag2_2_ngram3.end() )
         {
          const lem::MCollect<const LEMM_Ngram3*> & n3_list = * it->second;
      
          needs_resort=true;
      
          int proj_count = word2lemmas[iword].size();
          for( int iproj = 0; iproj < proj_count; ++iproj )
           {
            const lem::UCString & entry_name = word2lemmas[iword][iproj];
            lem::UCString i_sfx = GetSuffix( entry_name );
            if( sfx2score.find( i_sfx )==sfx2score.end() )
             sfx2score.insert( std::make_pair( i_sfx, 0 ) );
           }
      
          for( lem::Container::size_type j=0; j<n3_list.size(); ++j )
           {
            const LEMM_Ngram3 & n3_probe = *n3_list[j];
            const int id_suffix0 = n3_probe.tags.first;
            const lem::UCString & suffix0 = GetSuffixById(id_suffix0);
      
            std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix0);
            if( it2!=sfx2score.end() )
             it2->second += n3_probe.freq;
           }
         }
       }


      if( needs_resort )
       {
        // теперь надо выбрать самый достоверный вариант.
        int best_score = 0;

        lem::UCString prev_lemma;
        int prev_score = 0;

        // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
        for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj )
         {
          const lem::UCString & ename = word2lemmas[iword][iproj];
          lem::UCString proj_suffix = GetSuffix( ename );
          std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix);
          if( it3!=sfx2score.end() )
           {
            const int new_score = it3->second;
            if( new_score > best_score )
             {
              prev_score = new_score;
              prev_lemma = ename;
             }
           }
         }

        // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его.
        if( lemma_scores[iword] < prev_score )
         {
          lemma_scores[iword] = prev_score;
          lemmas[iword] = prev_lemma;
          lemma_order[iword] = 3;
         }
       }
     }
   } // конец триграм


   if( !lemma_created && use_2grams )
   {
    // ======================
    // ИСПОЛЬЗУЕМ ДИГРАММЫ
    // ======================

    // Если текущее слово имеет 1 вариант лемматизации, то можно использовать его для перепроверки предыдущего слова.
    if( iword>0 && word2lemmas[iword].size()==1 && word2lemmas[iword-1].size()>1 && lemma_order[iword-1]<2 )
    {
     // ...... [лемматизируемое_слово]  [опорное_слово] .......

     const lem::UCString & word2 = words[iword]; // опорное слово
     const int id_suffix2 = GetTag( word2 );

     std::map<int, lem::MCollect<const LEMM_Ngram2*>* >::const_iterator it = tag1_2_ngram2.find( id_suffix2 );
     if( it!=tag1_2_ngram2.end() )
      {
       const lem::MCollect<const LEMM_Ngram2*> & n2_list = * it->second;

       std::map<lem::UCString,int> sfx2score;

       int proj_count = word2lemmas[iword - 1].size();
       for( int iproj = 0; iproj < proj_count; ++iproj )
        {
         const lem::UCString & entry_name = word2lemmas[iword-1][iproj]; // вариант лемматизации лемматизируемого слова
         lem::UCString i_sfx = GetSuffix( entry_name );
         if( sfx2score.find( i_sfx )==sfx2score.end() )
          sfx2score.insert( std::make_pair( i_sfx, 0 ) );
        }

       for( lem::Container::size_type j=0; j<n2_list.size(); ++j )
        {
         const LEMM_Ngram2 & n2_probe = *n2_list[j];
         const int id_suffix1 = n2_probe.tags.first;
         const lem::UCString & suffix1 = GetSuffixById(id_suffix1);

         std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1);
         if( it2!=sfx2score.end() )
          it2->second += n2_probe.freq;
        }

       // теперь надо выбрать самый достоверный вариант.
       int best_score = 0;

       lem::UCString prev_lemma;
       int prev_score = 0;

       // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
       for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword - 1].size(); ++iproj )
        {
         const lem::UCString & ename = word2lemmas[iword - 1][iproj];
         lem::UCString proj_suffix = GetSuffix( ename );
         std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix);
         if( it3!=sfx2score.end() )
         {
          const int new_score = it3->second;
          if( new_score > best_score )
          {
           prev_score = new_score;
           prev_lemma = ename;
          }
         }
        }

       // Если предыдущее слово лемматизировано с меньшей достоверностью, то меняем его.
       if( lemma_scores[iword-1] < prev_score )
        {
         lemma_scores[iword-1] = prev_score;
         lemmas[iword-1] = prev_lemma;
         lemma_order[iword-1] = 2;
        }
      }
    }
    else if( word2lemmas[iword].size() > 1 && lemma_order[iword]<2 )
    {
     bool needs_resort=false;
     std::map<lem::UCString,int> sfx2score;

     if( iword>0 )
      {
       // ...... [опорное_слово]  [лемматизируемое_слово] .......
       const lem::UCString & word1 = words[iword-1];
       const int id_suffix1 = GetTag( word1 );
    
       std::map<int, lem::MCollect<const LEMM_Ngram2*>* >::const_iterator it = tag0_2_ngram2.find( id_suffix1 );
       if( it!=tag0_2_ngram2.end() )
        {
         needs_resort=true;
         const lem::MCollect<const LEMM_Ngram2*> & n2_list = * it->second;
   
         int proj_count = word2lemmas[iword].size();
         for( int iproj = 0; iproj < proj_count; ++iproj )
          {
           const lem::UCString & entry_name = word2lemmas[iword][iproj];
           lem::UCString i_sfx = GetSuffix( entry_name );
           if( sfx2score.find( i_sfx )==sfx2score.end() )
            sfx2score.insert( std::make_pair( i_sfx, 0 ) );
          }
    
         for( lem::Container::size_type j=0; j<n2_list.size(); ++j )
          {
           const LEMM_Ngram2 & n2_probe = *n2_list[j];
           const int id_suffix2 = n2_probe.tags.second;
           const lem::UCString & suffix2 = GetSuffixById(id_suffix2);
    
           std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix2);
           if( it2!=sfx2score.end() )
            it2->second += n2_probe.freq;
          }
        }
      }


     if( iword<last_word_index )
      {
       // iword <-- iword+1
       const lem::UCString & word2 = words[iword+1];
       const int id_suffix2 = GetTag( word2 );
    
       std::map<int, lem::MCollect<const LEMM_Ngram2*>* >::const_iterator it = tag1_2_ngram2.find( id_suffix2 );
       if( it!=tag1_2_ngram2.end() )
        {
         needs_resort=true;
         const lem::MCollect<const LEMM_Ngram2*> & n2_list = * it->second;
    
         int proj_count = word2lemmas[iword].size();
         for( int iproj = 0; iproj < proj_count; ++iproj )
          {
           const lem::UCString & entry_name = word2lemmas[iword][iproj];
           lem::UCString i_sfx = GetSuffix( entry_name );
           if( sfx2score.find( i_sfx )==sfx2score.end() )
            sfx2score.insert( std::make_pair( i_sfx, 0 ) );
          }
    
         for( lem::Container::size_type j=0; j<n2_list.size(); ++j )
          {
           const LEMM_Ngram2 & n2_probe = *n2_list[j];
           const int id_suffix1 = n2_probe.tags.first;
           const lem::UCString & suffix1 = GetSuffixById(id_suffix1);
    
           std::map<lem::UCString,int>::iterator it2 = sfx2score.find(suffix1);
           if( it2!=sfx2score.end() )
            it2->second += n2_probe.freq;
          }
        }
      }

     if( needs_resort )
      {
       // теперь надо выбрать самый достоверный вариант.
       int best_score = 0;

       lem::UCString prev_lemma;
       int prev_score = 0;

       // теперь перебираем проекции и смотрим, которая из них имеет в нормальной форме выбранный суффикс.
       for( lem::Container::size_type iproj = 0; iproj < word2lemmas[iword].size(); ++iproj )
        {
         const lem::UCString & ename = word2lemmas[iword][iproj];
         lem::UCString proj_suffix = GetSuffix( ename );
         std::map<lem::UCString,int>::const_iterator it3 = sfx2score.find(proj_suffix);
         if( it3!=sfx2score.end() )
          {
           const int new_score = it3->second;
           if( new_score > best_score )
            {
             prev_score = new_score;
             prev_lemma = ename;
            }
          }
        }

       // Если текущее слово лемматизировано с меньшей достоверностью, то меняем его.
       if( lemma_scores[iword] < prev_score )
        {
         lemma_scores[iword] = prev_score;
         lemmas[iword] = prev_lemma;
         lemma_order[iword] = 2;
        }
      }
    }
   }

  }

 return;
}
Exemple #25
0
void Lemmatizator::Lemmatize( const lem::UCString &word, lem::MCollect<lem::UCString> &lemmas )
{
 lem::UCString res(word);
 res.to_upper();

 bool rehash=false;
 for( int i=0; i<res.length(); ++i )
  if( res[i]==0x0401 )
   {
    res.set( i, 0x0415 );
    rehash=true;
   }

 if( rehash )
  res.calc_hash();

 // Определяем, в какой группе искать.
 const int igroup = (unsigned)res.GetHash16() & (L_NHASHGROUP-1);
 const lem::Stream::pos_type pos = group_pos[igroup];

 #if defined LEM_THREADS
 lem::Process::CritSecLocker lock(&cs);
 #endif

 // перемещается на начало группы в файле.
 bin->seekp(pos);

 // перебираем элементы группы в поисках нашей формы.
 const int n = bin->read_int();

 lem::uint8_t x8[3];

 if( char_size==sizeof(wchar_t) )
  {
   lem::UCString form;
   lem::MCollect<int> inorm;

   for( int i=0; i<n; ++i )
    {
     inorm.clear();
     lem::Load_Packed( &form, *bin );

     lem::uint8_t n8 = bin->read_uint8();
     inorm.reserve(n8);
     for( lem::uint8_t i8=0; i8<n8; ++i8 )
      {
       bin->read( x8, 3 );
       const int x32 = (0x00ff0000&(x8[0]<<16)) |
                       (0x0000ff00&(x8[1]<<8))  |
                       (0x000000ff&x8[2]);
       inorm.push_back(x32);
      } 
   
     if( form==res )
      {
       // Нашли!!!
       for( lem::Container::size_type j=0; j<inorm.size(); ++j )
        {
         lemmas.push_back( GetLemma(inorm[j]) );
        }

       return;
      }
    }
  }
 else if( char_size==1 )
  {
   lem::UCString form;
   lem::MCollect<int> inorm;

   for( int i=0; i<n; ++i )
    {
     inorm.clear();
     LoadEncodedString( &form, *bin, 1 );

     lem::uint8_t n8 = bin->read_uint8();
     inorm.reserve(n8);
     for( lem::uint8_t i8=0; i8<n8; ++i8 )
      {
       bin->read( x8, 3 );
       const int x32 = (0x00ff0000&(x8[0]<<16)) |
                       (0x0000ff00&(x8[1]<<8))  |
                       (0x000000ff&x8[2]);
       inorm.push_back(x32);
      } 
   
     if( form==res )
      {
       // Нашли!!!
       for( lem::Container::size_type j=0; j<inorm.size(); ++j )
        {
         lemmas.push_back( GetLemma(inorm[j]) );
        }

       return;
      }
    }
  }
 else
  {
   LEM_STOPIT;
  }

 lemmas.clear();

 // Табличной подстановки не нашлось, проверяем замену суффикса.
 for( lem::Container::size_type i=0; i<suffices.size(); ++i )
  {
   if( res.eq_endi( suffices[i].first ) )
    {
     // Нашли замену суффикса!
     UCString lemma = lem::left( res, res.length()-suffices[i].first.length() );
     lemma += suffices[i].second;
     lemmas.push_back(lemma);
     return;
    }
  }


 // Лемматизация не выполнена, возвращаем исходное слово в качестве леммы.
 lemmas.push_back(res);
 return;
}
Exemple #26
0
void BasicModel::PullFeatures1(
                               lem::MCollect<lem::CString> & b,
                               const lem::PtrCollect<ModelTokenFeatures> & token_features,
                               int ifocus,
                               int offset,
                               bool rich_set,
                               bool emit_Aa_feature
                              ) const
{
 int iword = ifocus + offset;

 if( iword >= 0 && iword < token_features.size() )
 {
  const ModelTokenFeatures & f = * token_features[iword];

  if( codebook->GetMaxSuffixLen() > 0 )
   b.push_back( lem::format_str( "sfx[%d]=%d", offset, f.suffix_id ).c_str() );

  if( emit_Aa_feature && f.Aa==true && !f.IsBegin && !f.IsEnd )
   b.push_back( lem::format_str( "Aa[%d]=True", offset ).c_str() );

  // здесь можно вывести и другие свойства слова.
  if( rich_set && EMIT_POS_TAGS )
  {
   b.push_back( lem::format_str("pos[%d,N]=%s", offset, f.POS_N.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,A]=%s", offset, f.POS_A.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,V]=%s", offset, f.POS_V.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,IMV]=%s", offset, f.POS_IMV.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,I]=%s", offset, f.POS_I.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,Y]=%s", offset, f.POS_Y.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,VY]=%s", offset, f.POS_VY.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PRN]=%s", offset, f.POS_PRN.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PRN2]=%s", offset, f.POS_PRN2.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,C]=%s", offset, f.POS_C.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,D]=%s", offset, f.POS_D.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,P]=%s", offset, f.POS_P.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PX]=%s", offset, f.POS_PX.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,PP]=%s", offset, f.POS_PP.c_str() ).c_str() );
   b.push_back( lem::format_str("pos[%d,MU]=%s", offset, f.POS_MU.c_str() ).c_str() );
  }

  if( EMIT_FORMTAGS_FOR_CONTEXT && offset!=0 )
   {
    for( int k = 0; k < f.allform_tags.size(); ++k )
    {
     b.push_back( lem::format_str("formtag[%d]=%d", offset, f.allform_tags[k] ).c_str() );
    }
   }

  if( EMIT_SEMANTIC_TAGS )
  {
   for( int k = 0; k < f.semantic_tags.size(); ++k )
   {
    b.push_back( lem::format_str("sem[%d]=%s", offset, lem::to_utf8( f.semantic_tags[k] ).c_str() ).c_str() );
   }
  }
 }

 return;
}
Exemple #27
0
bool GeneratorLexer::Fetch( const LexerTextPos * current, const TokenExpectation * unused, lem::MCollect<const LexerTextPos*> & next )
{
 if( current==NULL )
  {
   next.push_back( GetBeginToken() );
   return true;
  }

 if( current->IsEnd() )
  {
   return false;
  }

 next.clear();

 // поищем в кэше уже найденные продолжения.
 std::pair<CACHED_EDGES::const_iterator,CACHED_EDGES::const_iterator> p_edges = edges.equal_range(current);
 if( p_edges.first!=p_edges.second )
  {
   for( CACHED_EDGES::const_iterator it=p_edges.first; it!=p_edges.second; ++it )
    {
     next.push_back( it->second );
    }

   return true;
  }

 // Посмотрим, какие токены были перед данным, и какие слова они уже использовали.
 lem::MCollect<int> indeces;
 CollectUsedWords( current, indeces );

/*
#if LEM_DEBUGGING==1
if( current->GetWordform()->GetName()->eqi(L"ловит") )
 {
  lem::mout->printf("!\n");
 }
#endif
*/

 bool token_created=false;
 lem::MCollect<const LexerTextPos*> matched_by_literal_ngrams, matched_by_normalized_ngrams, all_next_tokens;

 lem::Ptr<Ngrams> ngrams;
 lem::UCString prev_lemma;

 if( UseNGrams )
  ngrams = dict->GetNgrams();

 // Теперь неиспользованные ранее слова порождают новые токены.
 for( lem::Container::size_type i=0; i<words.size(); ++i )
  if( indeces.find(i)==UNKNOWN )
   {
    // слово не использовалось.
    typedef INDEX2WORDFORM::const_iterator IT;
    std::pair<IT,IT> p = index2wordform.equal_range( CastSizeToInt(i) );

    for( IT it=p.first; it!=p.second; ++it )
     {
      const Word_Form * wordform = it->second;
      const int word_index = current->IsRealWord() ? current->GetWordIndex()+1 : 0;
      const int start_pos = current->IsRealWord() ? (current->GetStartPosition()+current->GetWordLength()+1) : 0;

      // Нам нужно создать новый вариант этой словоформы.
      Word_Form * wf = new Word_Form( *wordform, true );
      wf->SetOriginPos( word_index );
      wordforms.push_back(wf);

      LexerTextPos * new_token = new LexerTextPos( current, wf, 0, start_pos, wf->GetName()->length(), word_index );
      positions.push_back(new_token);

      all_next_tokens.push_back( new_token );

      token2word.insert( std::make_pair(new_token,CastSizeToInt(i)) );

      token_created = true;

      // Слово сочетается с предыдущим?
      if( UseNGrams && current->IsRealWord() )
       {
        const lem::UCString & prev_word = * current->GetWordform()->GetNormalized();
        const lem::UCString & new_word = * new_token->GetWordform()->GetNormalized();
        
        float w2=0;
        int iw2=0;
        if( ngrams->FindLiteralNGrams( prev_word, new_word, w2, iw2 ) )
         {
          // TODO: использовать частотность подошедшей N-граммы для взвешивания созданных токенов.
          matched_by_literal_ngrams.push_back( new_token );
         }
        else
         {
          if( prev_lemma.empty() )
           {
            const int prev_ekey = current->GetWordform()->GetEntryKey();
            const SG_Entry & prev_e = dict->GetSynGram().GetEntry( prev_ekey );
            prev_lemma = prev_e.GetName();
           }

          const int new_ekey = new_token->GetWordform()->GetEntryKey();
          const SG_Entry & new_e = dict->GetSynGram().GetEntry( new_ekey );
          const lem::UCString & new_lemma = new_e.GetName();

          if( ngrams->FindRawNGrams( prev_lemma, new_lemma, w2, iw2 ) )
           {
            // TODO: использовать частотность подошедшей N-граммы для взвешивания созданных токенов.
            matched_by_normalized_ngrams.push_back( new_token );
           }
         }
       }
     }
   }

 if( !matched_by_literal_ngrams.empty() )
  {
   // найдена по крайней мере одна буквальная 2-грамма, поэтому отбрасываем все неподтвержденные варианты токенов.
   next = matched_by_literal_ngrams;
  }
 else if( !matched_by_normalized_ngrams.empty() )
  {
   next = matched_by_normalized_ngrams;
  }
 else
  {
   next = all_next_tokens;
  }

 for( lem::Container::size_type i=0; i<next.size(); ++i )
  {
   edges.insert( std::make_pair(current, const_cast<LexerTextPos*>( next[i] ) ) );
  }


/*
 #if LEM_DEBUGGING==1
 lem::mout->printf( "%60h-\n" );
 for( lem::Container::size_type i=0; i<next.size(); ++i )
  {
   lem::mout->printf( "FETCHED: %us(%p) -> %us(%p)\n", current->GetWordform()->GetName()->c_str(), current, next[i]->GetWordform()->GetName()->c_str(), next[i] );
  }
 #endif
*/


 if( !token_created )
  {
   // Возвращаем правую границу.
   next.push_back( GetEndToken(current) );
   return true;
  }

 return false;
}