void Solarix::PrintTags( SG_TagsList tags, lem::UFString &str, SynGram &sg ) { str.clear(); if( tags!=NULL ) { for( lem::Container::size_type i=0; i<tags->size(); ++i ) { const int itag = (*tags)[i].first; const int ival = (*tags)[i].second; const ThesaurusTag &tag = sg.Get_Net().GetTagDefs()[itag]; if( !str.empty() ) str += L' '; str += tag.GetName().c_str(); if( ival!=UNKNOWN ) { const lem::UCString &val = tag[ival]; str += L'='; str += val.c_str(); } } } return; }
lem::Path lem::sqlite_get_absolute_filepath( const lem::UFString & connection_string ) { lem::Path sqlite_file; if( connection_string.eq_begi(L"path=") || connection_string.eq_begi(L"file=") ) { lem::UFString db_path, db_file, basedir; lem::Collect<UFString> params; lem::parse( connection_string, params, L";" ); for( lem::Container::size_type i=0; i<params.size(); ++i ) { const lem::UFString & param = params[i]; if( param.eq_begi(L"path=") ) db_path = param.c_str()+5; else if( param.eq_begi(L"file=") ) db_file = param.c_str()+5; } if( !db_path.empty() ) sqlite_file = lem::Path(db_path); else { sqlite_file = lem::Path(basedir); sqlite_file.ConcateLeaf(db_file); } } else { sqlite_file = lem::Path(connection_string); } return sqlite_file; }
// Считываем символы до закрывающей ) // Возвращает true, если последний токен перед ) был терминатором предложения. bool SentenceBroker::ReadCharsUntilClosingParen(lem::UFString & line) { int n_paren = 1; lem::UCString unbreakable; bool last_is_sentence_terminator = false; while (!Eof() || !chars.empty()) { wchar_t c = GetChar(); if (c == WEOF) { eof = true; break; } if (lem::is_uspace(c)) { line += L' '; if (line.length() >= max_sentence_length) break; } else { // считаем символ или группу неразрывных символов. ReadCharOrUnbreakable(c, unbreakable); if (unbreakable == L')') { line += unbreakable.front(); n_paren--; if (!n_paren) break; } else if (unbreakable == L'(') { line += unbreakable.front(); n_paren++; last_is_sentence_terminator = false; } else { line += unbreakable.c_str(); last_is_sentence_terminator = sent_delims.find(unbreakable) != UNKNOWN; } if (line.length() >= max_sentence_length * 2) break; } } return last_is_sentence_terminator; }
void WrittenTextAnalysisSession::AnalyzeIt(const lem::UFString & str, bool ApplyPatterns, bool DoSyntacticLinks, const ElapsedTimeConstraint & constraints) { processed_str = str; if (params.LanguageUnknown()) { // Язык предложения не задан явно, определим его на основе статистических критериев. const int id_language = dict->GetLexAuto().GuessLanguage(str); if (id_language == UNKNOWN) { lem::MemFormatter msg; msg.printf("Can not guess the language of the phrase [%us]", str.c_str()); throw E_BaseException(msg.string()); } params.SetLanguageID(id_language); #if defined SOL_DEBUGGING if (trace != nullptr) { trace->LanguageGuessed(str, id_language); } #endif } delete lexer; lexer = new WrittenTextLexer(str, params, dict, trace); Analyze(ApplyPatterns, DoSyntacticLinks, constraints); return; }
WordFormEnumeratorGlobbing_File::WordFormEnumeratorGlobbing_File( WordEntries_File * _entries, const lem::UFString &_mask ) : WordFormEnumeratorListing_File(_entries), mask(_mask) { LEM_CHECKIT_Z(!_mask.empty()); return; }
void CasingCoder::AddUpper( const CasingCoder::XLAT *xlat, lem::uint32_t src_ch, lem::UFString &res ) const { for( lem::Container::size_type i=0; i<xlat->upper_xlat.size(); ++i ) { lem::uint32_t res_ch = xlat->upper_xlat[i]->Apply(src_ch); if( res_ch!=src_ch ) { Ucs4ToUCString x; x.Add(res_ch); res.Add_Dirty( x.ToString().c_str() ); return; } } Ucs4ToUCString x; x.Add(src_ch); res.Add_Dirty( x.ToString().c_str() ); return; }
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; }
SG_DeclensionForm::SG_DeclensionForm( const lem::UFString & lexem_generator, const lem::UFString & rx_condition, const lem::UFString & rx_flexer_flags, const CP_Array & dims ) : dim(dims), form(lexem_generator.c_str()) { valid_condition = !rx_condition.empty(); valid_flexer_flags = !rx_flexer_flags.empty(); condition_str = rx_condition; flexer_flags_str = rx_flexer_flags; if( !condition_str.empty() ) condition = boost::wregex( condition_str.c_str(), boost::basic_regex<wchar_t>::icase ); if( !flexer_flags.empty() ) flexer_flags = boost::wregex( flexer_flags_str.c_str(), boost::basic_regex<wchar_t>::icase ); return; }
void SG_Language::SubstParadigmPattern(lem::UFString &pattern) const { for (lem::Container::size_type i = 0; i < params.size(); ++i) { if (params.get(i)->name.eqi(L"ParadigmSubst")) { if (params[i]->values.size() != 2) { const Solarix::SG_LanguageParam & p = *params[i]; // ... LEM_STOPIT; } const UFString &from = params[i]->values.front(); const UFString &to = params[i]->values.back(); pattern.subst_all(from, to); } } return; }
void TreeScorerResult::DeserializeExpression( int expr_type, const lem::UFString & serialized ) { type=expr_type; if( type==NumberScoreType ) { score = lem::to_int( serialized); } else if( type==NGramScoreType ) { lem::StrParser<lem::UFString> txt(serialized); id_fact = lem::to_int( txt.read() ); txt.read_it( L"(" ); while( !txt.eof() ) { if( txt.probe( L")" ) ) break; if( !args.empty() ) txt.read_it(L","); args.push_back( lem::UCString(txt.read().c_str()) ); } } else if( type==FuncScoreType ) { lem::MemReadHexStream bin2( serialized.c_str() ); args.LoadBin(bin2); score_fun = TrFunCall::load_bin(bin2); } else { LEM_STOPIT; } return; }
bool SyntaxShell::TryCommand( const lem::UFString &_str ) { LEM_CHECKIT_Z( !_str.empty() ); if( _str==L"#help" || _str==L"?" ) { ShowHelp(); return true; } if( _str.front()!=L'#' ) return false; if( _str.eq_beg( L"# " ) ) return true; // комментарий if( _str.eq_beg( L"#timeout" ) ) { lem::MCollect<UCString> toks; lem::parse( _str, toks, false ); MaxTimeout = lem::to_int( toks[1] ); return true; } if( _str.eq_beg( L"#maxalt" ) ) { lem::MCollect<UCString> toks; lem::parse( _str, toks, false ); MaxAlt = lem::to_int( toks[1] ); lem::mout->printf( "MaxAlt=%d\n", MaxAlt ); return true; } if( _str.eq_beg( L"#maxskiptoken" ) ) { lem::MCollect<UCString> toks; lem::parse( _str, toks, false ); MaxSkipToken = lem::to_int( toks[1] ); lem::mout->printf( "MaxSkipToken=%d\n", MaxSkipToken ); if( MaxSkipToken>0 ) CompleteAnalysisOnly = false; if( MaxAlt==0 || MaxAlt==lem::int_max ) { lem::mout->printf( "Attention: it is highly recommended to use %vfE#maxalt%vn NNN in order to limit the search tree depth\n" ); } return true; } if( _str.eq_beg( L"#sem" ) ) { lem::MCollect<UCString> toks; lem::parse( _str, toks, false ); FindFacts = lem::to_bool( toks[1] ); return true; } if( _str.eqi( L"#info" ) ) { ShowDictionaryInfo(); return true; } if( _str.eqi( L"#disconnect" ) ) { sol_id.Delete(); lem::mout->printf( "Dictionary database is disconnected.\n" ); return true; } if( _str.eqi( L"#connect" ) ) { LoadDictionary(); return true; } if( _str.eq_begi( L"#tag" ) ) { if( _str==L"#tag-" ) { // Сбрасываем установленный фильтр tags_ptr.Delete(); tags.clear(); return true; } lem::Collect<lem::UFString> toks; lem::parse( UFString(_str.c_str()+4), toks, L"=" ); UCString tag_name, tag_value; if( toks.size()>0 ) tag_name = toks[0].c_str(); if( toks.size()>1 ) tag_value = toks[1].c_str(); tag_name.trim(); tag_value.trim(); const int itag = sol_id->GetSynGram().Get_Net().FindTag(tag_name); if( itag==UNKNOWN ) { lem::mout->printf( "Tag [%vfE%us%vn] not found\n", tag_name.c_str() ); return true; } const ThesaurusTag &tt = sol_id->GetSynGram().Get_Net().GetTagDefs()[itag]; if( tt.CountValues()>0 ) { int ivalue = tt[tag_value]; if( ivalue==UNKNOWN ) { lem::mout->printf( "Tag value [%vfE%us%vn] not found\n", tag_value.c_str() ); return true; } } tags_ptr = new TF_TagOrNullFilter( *sol_id, tag_name, tag_value ); return true; } if( _str.eq_begi( L"#param" ) ) { if( _str==L"#param-" ) { // Очищаем список параметров. params.clear(); return true; } lem::Collect<lem::UFString> toks; lem::parse( UFString(_str.c_str()+7), toks, L"=" ); UCString param_name, param_value; if( toks.size()>0 ) param_name = toks[0].c_str(); if( toks.size()>1 ) param_value = toks[1].c_str(); param_name.trim(); param_value.trim(); params.push_back( std::make_pair( param_name, param_value ) ); return true; } lem::UFString str = lem::right( _str, _str.length()-1 ); lem::zbool ret; if( str==L"debug" ) { SetDebug(true); ret=true; } else if( str==L"nodebug" ) { SetDebug(false); ret=true; } else if( str==L"traceon" ) { SetDebug(true); traceon=true; debugger->Trace(true); ret=true; } else if( str==L"traceoff" ) { traceon=false; if( debugger.NotNull() ) debugger->Trace(true); ret=true; } else if( str==L"fuzzyon" ) { allow_fuzzy = true; mout->printf( "Fuzzy projection is now %vfAON%vn\n" ); ret=true; } else if( str==L"fuzzyoff" ) { allow_fuzzy = false; mout->printf( "Fuzzy projection is now %vfDOFF%vn\n" ); ret=true; } else if( str=="disable_filters" ) { EnableFilters=false; ret = true; } else if( str=="enable_filters" ) { EnableFilters=true; ret = true; } else if( str=="schedule1" ) { CompleteAnalysisOnly=true; UseTopDownThenSparse=true; mout->printf( "Workflow=%vfATOP-DOWN, TOP-DOWN INCOMPLETE%vn\n" ); ret=true; } else if( str==L"topdown" ) { UseTopDownThenSparse=false; CompleteAnalysisOnly=true; mout->printf( "%vfAtop-down%vn analyzer is activated\n" ); ret=true; } else if( str==L"allow_incomplete" ) { CompleteAnalysisOnly = false; mout->printf( "Incomplete analysis is %vfAALLOWED%vn\n" ); ret=true; } else if( str==L"disallow_incomplete" ) { CompleteAnalysisOnly = true; mout->printf( "Incomplete analysis is %vfDDISALLOWED%vn\n" ); ret=true; } else if( str==L"allow_reco" ) { UseReconstructor = true; mout->printf( "Token reconstructor is %vfAALLOWED%vn\n" ); ret=true; } else if( str==L"disallow_reco" ) { UseReconstructor = false; mout->printf( "Token reconstructor is %vfDDISALLOWED%vn\n" ); ret=true; } else if( str==L"allow_model" ) { if( sol_id->GetLexAuto().GetModel().GetSequenceLabeler().IsAvailable() || sol_id->GetLexAuto().GetModel().GetClassifier().IsAvailable() ) { ApplyModel = true; mout->printf( "Morphology model is enabled\n" ); } else { mout->printf( "Morphology model is not available\n" ); } ret=true; } else if( str==L"disallow_model" ) { ApplyModel = false; mout->printf( "Morphology model is disabled\n" ); ret=true; } else if( str==L"show" ) { if( current_analysis.NotNull() ) { const Res_Pack &pack = current_analysis->GetPack(); mout->printf( "\nResult pack contains %vfE%d%vn variators:\n", pack.vars().size() ); if( run_mode==MorphologyMode ) { for( lem::Container::size_type i=0; i<pack.vars().size(); i++ ) { const Variator * var = pack.vars()[i]; for( lem::Container::size_type k=0; k<var->size(); ++k ) { const Tree_Node & root = var->get(k); mout->printf( "%d: ", CastSizeToInt(k) ); root.Print( *lem::mout, sol_id->GetSynGram(), -1, true ); mout->eol(); } mout->eol(); mout->eol(); } } else { for( lem::Container::size_type i=0; i<pack.vars().size(); i++ ) { pack.vars()[i]->PrintV( *mout, sol_id->GetSynGram(), true ); mout->eol(); mout->eol(); } } } ret=true; } else if( str==L"tree" ) { if( current_analysis.NotNull() ) { const Res_Pack &pack = current_analysis->GetPack(); Solarix::print_syntax_tree( current_analysis->GetString(), current_analysis->GetPack(), *sol_id, *lem::mout, false, true ); } ret=true; } else if( str.eq_beg("recog" ) ) { if( current_analysis.NotNull() ) { lem::mout->eol(); current_analysis->GetLexer().PrintRecognitions( *lem::mout ); } return true; } else if( str==L"tokenize" ) { SetMode(TokenizerMode); ret=true; } else if( str==L"lemmatize" ) { SetMode(LemmatizerMode); ret=true; } else if( str==L"speak" ) { SetMode(SpeakerMode); ret=true; } else if( str==L"syntax" ) { SetMode(SyntaxMode); ret=true; } else if( str==L"morphology" ) { SetMode(MorphologyMode); ret=true; } else if( str==L"debugger" ) { if( debugger.NotNull() ) debugger->ManageBreakpoints(); ret=true; } else { lem::mout->printf( "Invalid command %vfC%us%vn\n", str.c_str() ); ret=true; } return ret; }
void lem::sqlite_escape( lem::UFString &str ) { str.subst_all( L"'", L"''" ); return; }
void LexicalAutomat::TranslateLexem( lem::UFString &str, bool substitute_entries, int LanguageID ) { WideStringUcs4 cenum(str.c_str()); lem::uint32_t c; lem::uint32_t prev_c=0; lem::Ucs4ToUFString yield; while( (c=cenum.Fetch())!=0 ) { if( c==L' ' ) { // Оставляем всегда единственный пробел (точнее - символ разделения лексем // в мультилексеме). if( prev_c!=Lexem::DelimiterChar ) { yield.Add(Lexem::DelimiterChar); prev_c = c; } continue; } if( c==L'-' || c==L',' || c==L'\'' ) { if( prev_c!=Lexem::DelimiterChar && prev_c!=0 ) yield.Add(Lexem::DelimiterChar); yield.Add(c); if( cenum.Fetch()!=0 ) { yield.Add( Lexem::DelimiterChar ); cenum.Back(); } prev_c = Lexem::DelimiterChar; continue; } Word_Coord wc; if( LanguageID==ANY_STATE ) wc = GG->FindSymbol(c); else if( LanguageID==UNKNOWN ) wc = GG->FindSymbol(c,GetDefaultAlphabets()); else wc = GG->FindSymbol(c,LanguageID); if( wc.GetEntry()==UNKNOWN ) { // Символ не найден в графической грамматике. yield.Add(c); } else { const GG_Entry &entry = GG->entries()[ wc.GetEntry() ]; if( !substitute_entries || wc.GetForm()==UNKNOWN || wc.GetForm()==ANY_STATE ) yield.Add( entry.GetForm(wc.GetForm()).GetName() ); else yield.Add( entry.GetName() ); } prev_c = c; } str = yield.ToString(); return; }
void SG_ComplexLink::LoadPoint( Macro_Parser &txtfile, SynGram &gram, lem::UFString &entry ) { BethToken t = txtfile.read(); if( t.GetToken()==B_ENTRY ) { // Особый формат entry Класс:Статья { уточнение } // преобразуется в ключ статьи и возвращается в виде #ключ UCString class0 = txtfile.read().string(); const int ic0 = class0==L"?" ? ANY_STATE : gram.FindClass(class0); if( ic0==UNKNOWN ) { Print_Error( txtfile ); gram.GetIO().merr().printf( "Unknown class %us\n", class0.c_str() ); throw E_BaseException(); } txtfile.read_it( B_COLON ); UCString entry0 = sol_read_multyname( gram.GetIO(), txtfile, B_OFIGPAREN ); entry0.strip(L'"'); entry0.trim(); // Может быть задана дополнительная фильтрующая координата Solarix::CP_Array coords0; coords0.LoadTxt( txtfile, gram ); if( gram.IsOmonym(ic0,lem::to_upper(entry0)) && coords0.empty() ) { Print_Error( txtfile ); gram.GetIO().merr().printf( "Omonym %us:%us requires the coordinate array\n", class0.c_str(), entry0.c_str() ); throw E_BaseException(); } const int ie0 = coords0.empty() ? gram.FindEntry(entry0,ic0,false) : gram.FindEntryOmonym(entry0,ic0,coords0); if( ie0==UNKNOWN ) { Print_Error( txtfile ); gram.GetIO().merr().printf( "Unknown entry %us:%us\n", class0.c_str(), entry0.c_str() ); throw E_BaseException(); } const int ekey = gram.GetEntry(ie0).GetKey(); entry = lem::format_str( L"#%d", ekey ); return; } bool figparen = t.GetToken()==B_OFIGPAREN; if( !figparen ) txtfile.seekp(t); entry.reserve(128); if( t.string()==L'@' ) { entry = L'@'; t = txtfile.read(); } while( !txtfile.eof() ) { BethToken t = txtfile.read(); if( figparen && t.GetToken()==B_CFIGPAREN ) break; if( !entry.empty() ) entry.Add_Dirty(L' '); UFString ts( t.GetFullStr() ); ts.strip(L'"'); entry.Add_Dirty( ts ); if( !figparen ) break; } entry.calc_hash(); if( entry.front()==L'@' ) { // Спецсимвол @ заставляет запомнить строку в виде "как есть" entry.remove(0); entry.trim(); } else { entry.strip(L'"'); gram.GetDict().GetLexAuto().TranslateLexem(entry,true); } return; }
void CasingCoder::RestoreCasing( int external_casing_state, lem::UFString &res, int ekey ) { if( (ekey!=UNKNOWN && ekey==UnknownEntries_ekey ) ) return; const XLAT *xlat = GetXLAT(ekey); switch( x(external_casing_state) ) { case 1: { if( xlat->use_unicode ) { res.to_Aa(); } else { WideStringUcs4 src_enum( res.c_str() ); lem::UFString out; out.reserve(res.length()+1); for( int i=0; ; ++i ) { const lem::uint32_t src_ucs4 = src_enum.Fetch(); if(!src_ucs4) break; if(i==0) AddUpper( xlat, src_ucs4, out ); else AddLower( xlat, src_ucs4, out ); } res = out; } break; } case 2: { if( xlat->use_unicode ) { res.to_upper(); } else { WideStringUcs4 src_enum( res.c_str() ); lem::UFString out; out.reserve(res.length()+1); for(;;) { const lem::uint32_t src_ucs4 = src_enum.Fetch(); if(!src_ucs4) break; AddUpper( xlat, src_ucs4, out ); } res = out; } break; } case 3: { if( xlat->use_unicode ) { Solarix::MakeEachLexemAa(res); } else { bool capitalize=true; WideStringUcs4 src_enum( res.c_str() ); lem::UFString out; out.reserve(res.length()+1); for(;;) { const lem::uint32_t src_ucs4 = src_enum.Fetch(); if(!src_ucs4) break; if( capitalize ) { AddUpper( xlat, src_ucs4, out ); capitalize=false; } else { AddLower( xlat, src_ucs4, out ); if( src_ucs4==L' ' || src_ucs4==L'-' ) capitalize=true; } } res = out; } break; } case 0: default: { if( xlat->use_unicode ) { res.to_lower(); } else { WideStringUcs4 src_enum( res.c_str() ); lem::UFString out; out.reserve(res.length()+1); for(;;) { const lem::uint32_t src_ucs4 = src_enum.Fetch(); if(!src_ucs4) break; AddLower( xlat, src_ucs4, out ); } res = out; } break; } } // res.subst_all( L" - ", L"-" ); // res.subst_all( L" ' ", L"'" ); return; }
bool SentenceBroker::Fetch(lem::UFString &line, int & line_paragraph_id) { line.clear(); line_paragraph_id = cur_paragraph_id; if (eof) return false; int n_quote = 0; // для учета символов " // Пропустим начальные пробелы. while (!eof) { wchar_t c = GetChar(); if (c == WEOF) { break; } if (!lem::is_uspace(c) || IsEndOfSentenceMarker(c)) { UngetChar(c); break; } } while (!eof || !chars.empty()) { wchar_t c = GetChar(); if (c == WEOF) { eof = true; return true; } else if (c == L' ') { line += c; continue; } else if (IsEndOfSentenceMarker(c)) { line += c; break; } bool line_ready = false; if ( (line.empty() || IsTokenDelimiter(line.back()) || IsTokenDelimiter(c)) && tokenizer.NotNull() && tokenizer->IsUnbreakableFront(c) ) { // Возможно далее идет исключительный случай. Выбираем символы из входного потока в // попытке сконструировать максимально длинное исключение. lem::UCString substr; substr = c; while (!eof) { wchar_t c2 = GetChar(); if (c2 == WEOF) { // Достигли конца файла. Считали полный исключительный случай? if (tokenizer->IsMatched(substr)) { // Да! line += substr.c_str(); c = c2; // Считанный токен является разделителем предложений (типа ...) if (sent_delims.find(substr) != UNKNOWN) { line.trim(); if (!line.empty() && (n_quote % 2) == 0) { count++; return true; } } } else { // нет - вернем накопленные символы в поток чтения for (int k = substr.length() - 1; k >= 0; --k) UngetChar(substr[k]); c = GetChar(); } break; } substr += c2; // добавили еще один символ. // С символов substr начинается хоть одно исключение? if (!tokenizer->IsUnbreakableFront(substr) || substr.length() == lem::UCString::max_len) { // Нет. // Возможно, предыдущая подстрока является исключительной ситуацией. UCString substr1 = lem::left(substr, substr.length() - 1); if (tokenizer->IsMatched(substr1) && IsTokenDelimiter(substr.back())) { // Да! line += substr1.c_str(); // Считанный токен является разделителем предложений (типа ...) if (sent_delims.find(substr1) != UNKNOWN) { if ((n_quote % 2) == 0) { line.trim(); if (!line.empty()) { UngetChar(c2); count++; return true; } } else { if (c2 == L'"') { // Ситуация типа Кошка говорит "Мяу!" Собака говорит "Гав!" bool continuation_found = true; lem::MCollect<wchar_t> tmp_chars; while (!eof || !chars.empty()) { const wchar_t c4 = GetChar(); tmp_chars.push_back(c4); if (!lem::is_uspace(c4)) { if (IsUpperChar(c4)) { continuation_found = false; } break; } } for (int k = CastSizeToInt(tmp_chars.size()) - 1; k >= 0; --k) UngetChar(tmp_chars[k]); if (!continuation_found) { line += c2; return true; } } } } #if defined SOL_CAA // Если считанный токен делит предложения в случае, когда за ним // идет слово с первой заглавной буквой. if (use_lexicon && casing_sent_delim.find(to_lower(substr1)) != UNKNOWN && CharCasingCoord != UNKNOWN && LowerCasingState != UNKNOWN) { Lexem next_token = PickNextToken(); if (IsUpperChar(next_token.front())) { la->TranslateLexem(next_token); int ie = UNKNOWN; if (seeker != NULL) { ie = seeker->Find(next_token, false); } else { MCollect<Word_Coord> found_list; la->ProjectWord(next_token, found_list, LanguageID); if (!found_list.empty()) ie = found_list.front().GetEntry(); } if (ie != UNKNOWN) { const Solarix::SG_Entry &e = sg->GetEntry(ie); const int casing = e.attrs().FindOnce(Solarix::GramCoordAdr(CharCasingCoord)); if (casing == LowerCasingState || casing == UNKNOWN) { UngetChar(c2); count++; return true; } } } } #endif c = c2; } else { // Возвращаем все загруженные символы обратно в поток. for (int k = substr.length() - 1; k >= 0; --k) UngetChar(substr[k]); c = GetChar(); } break; } } } if (c == WEOF) { // закончился исходный текст, принудительно прерываем текущее предложение. eof = true; return true; } const bool ItIsSentDelim = sent_delims1.find(c) != UNKNOWN; if (ItIsSentDelim) { if (IsEndOfSentenceMarker(c)) break; // Обычный конец предложения. Для точки надо проверять, если сразу после точки идет цифра // или символ в нижнем регистре, то это НЕ конец предложения. bool breaker = false; bool add_char = true; // Если у нас есть незакрытая пара ", то проверим следующий непустой символ. if ((n_quote % 2) != 0) { const wchar_t c2 = GetChar(); // Если это закрывающая " if (c2 == L'"') { n_quote++; line += c; line += c2; const wchar_t c4 = GetChar(); if (sent_delims1.find(c4) != UNKNOWN) { line += c4; count++; return true; } else { UngetChar(c4); } // если дальше - пробел, и после него идет символ в нижнем регистре, то это не конец предложения. bool continuation_found = true; UFString tmp_chars; while (!eof) { const wchar_t c5 = GetChar(); if (c5 == WEOF) { break; } tmp_chars += c5; if (!lem::is_uspace(c5)) { // найден не-пробельный символ. if (IsUpperChar(c5)) { continuation_found = false; } break; } } // возвращаем все символы обратно for (int i = CastSizeToInt(tmp_chars.size()) - 1; i >= 0; --i) UngetChar(tmp_chars[i]); if (!continuation_found) { // обрываем предложение. line.trim(); count++; return true; } } else { // нет - продолжим считывание символов предложения. line += c; line += c2; } } else { #if defined SOL_CAA if (tokenizer.NotNull() && seeker.NotNull() && use_lexicon && c == L'.') { // надо выделить слово, предшествующее точке. идем влево до разделителя токенов. int icur = line.length() - 1; while (icur >= 0) { if (tokenizer->IsTokenDelimiter(line[icur])) break; // нашли начало последнего слова else icur--; // сдвигаемся влево } Solarix::Lexem last_word; for (int j = icur + 1; j < line.length(); ++j) last_word.Add_Dirty(line[j]); last_word.calc_hash(); la->TranslateLexem(last_word); if (seeker->Find(last_word, false) != UNKNOWN) { breaker = true; } } #endif if (!breaker) { breaker = true; wchar_t c2 = PeekChar(); if (c == L'.') { if (lem::is_udigit(c2)) { breaker = false; } else if (IsLowerChar(c2)) { breaker = false; } else if (c2 == L',') { breaker = false; } else if (lem::is_uspace(c2)) { // Дойдем до первого не-пробельного символа. line += c; add_char = false; while (c != WEOF) { c = GetChar(); line += c; if (IsEndOfSentenceMarker(c)) break; c = PeekChar(); if (!lem::is_uspace(c)) { if (IsLowerChar(c)) { breaker = false; } break; } } c = L'.'; } wchar_t c0 = c; c2 = PeekChar(); if (c2 == c0) { line += c; add_char = false; while (c != WEOF && c == c0) { c = GetChar(); line += c; c = PeekChar(); } } } else if (c == '!' || c == '?') { wchar_t c0 = c; c2 = PeekChar(); if (c2 == L'?' || c2 == L'!') // То есть токены типа !!! и !? { line += c; add_char = false; while (c != WEOF && (c == L'!' || c == L'?')) { c = GetChar(); line += c; c = PeekChar(); } } } } if (c == WEOF) { eof = true; add_char = false; } if (breaker) { line_ready = true; } if (add_char) line += c; } } else if (line.length() > max_sentence_length && (lem::is_uspace(c) || c == L',' || c == L'-' || c == L';' || c == L':')) { // Слишком длинные предложения обрываем на безопасных символах. line_ready = true; line += c; } else if (c == L'\r' || c == L'\n' || c == L'\t' || c == L'\b') { // некоторые управляющие символы заменяем пробелами line += L' '; } else { line += c; if (c == L'"') n_quote++; else if (c == L'(') { // если предложение начинается с (, то надо смотреть, какой токен будет перед ), и если это терминатор - обрывать предложение. if (line.size() == 1) { if (ReadCharsUntilClosingParen(line)) { line.trim(); return true; } } else { ReadCharsUntilClosingParen(line); } } } if (line_ready) { if (line.length() > 0 && IsEndOfParagraphMarker(line.last_char())) { line.remove(line.length() - 1); cur_paragraph_id++; } line.trim(); if (!line.empty()) count++; return true; } } if (line.length() > 0 && IsEndOfParagraphMarker(line.last_char())) { line.remove(line.length() - 1); cur_paragraph_id++; } line.trim(); if (!line.empty()) count++; return true; }
int SegmentingSentenceTokenizer::MatchLen(const lem::UFString & s, int i0) const { return lookup->match_len(s.c_str() + i0); }