예제 #1
0
// Считываем символы до закрывающей )
// Возвращает 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;
}
예제 #2
0
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.Add_Dirty(c);
     continue;
    }
   else if( IsEndOfSentenceMarker(c) )
    {
     line.Add_Dirty(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.Add_Dirty( substr.c_str() );
           c = c2;

           // Считанный токен является разделителем предложений (типа ...)
           if( sent_delims.find(substr)!=UNKNOWN )
            {
             line.calc_hash();
             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.Add_Dirty( substr1.c_str() );

           // Считанный токен является разделителем предложений (типа ...)
           if( sent_delims.find(substr1)!=UNKNOWN )
            {
             if( (n_quote%2)==0 )
              {
               line.calc_hash();
               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.Add_Dirty( 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.Add_Dirty( c );
         line.Add_Dirty( c2 );

         const wchar_t c4 = GetChar();
         if( sent_delims1.find(c4)!=UNKNOWN )
          {
           line.Add_Dirty( 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.Add_Dirty(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.Add_Dirty( c );
         line.Add_Dirty( 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.Add_Dirty( c );
    
             add_char=false;
             while( c!=WEOF )
              {
               c = GetChar();
               line.Add_Dirty( 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.Add_Dirty( c );
             add_char=false;
             while( c!=WEOF && c==c0 )
              {
               c = GetChar();
               line.Add_Dirty( c );
               c = PeekChar();
              } 
            }    
          }
         else if( c=='!' || c=='?' )
          {
           wchar_t c0 = c;
           c2 = PeekChar();
           if( c2==L'?' || c2==L'!' ) // То есть токены типа !!! и !?
            {
             line.Add_Dirty( c );
             add_char=false;
             while( c!=WEOF && (c==L'!' || c==L'?') )
              {
               c = GetChar();
               line.Add_Dirty( c );
               c = PeekChar();
              } 
            }
          }
        }
    
       if( c==WEOF )  
        {
         eof = true;
         add_char=false;
        } 
    
       if( breaker )
        {
         line_ready=true;
        }
    
       if( add_char )
        line.Add_Dirty( c );
      }
    }
   else if( line.length()>max_sentence_length && (lem::is_uspace(c) || c==L',' || c==L'-' || c==L';' || c==L':' ) )
    {
     // Слишком длинные предложения обрываем на безопасных символах.
     line_ready=true;
     line.Add_Dirty( c );
    }
   else if( c==L'\r' || c==L'\n' || c==L'\t' || c==L'\b' )
    {
     // некоторые управляющие символы заменяем пробелами
     line.Add_Dirty( L' ' );
    }
   else
    {
     line.Add_Dirty( 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.calc_hash();
     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.calc_hash();
 line.trim();

 if( !line.empty() )
  count++;

 return true;
}
예제 #3
0
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;
}