// Считываем символы до закрывающей ) // Возвращает 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.Add_Dirty(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.Add_Dirty( unbreakable.front() ); n_paren++; last_is_sentence_terminator=false; } else { line.Add_Dirty( unbreakable.c_str() ); last_is_sentence_terminator = sent_delims.find(unbreakable)!=UNKNOWN; } if( line.length()>=max_sentence_length*2 ) break; } } line.calc_hash(); return last_is_sentence_terminator; }
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; }
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; }
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; }
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; }