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; }
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; }
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; }
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; }