Склонение ФИО по падежам

Алгоритмы: от сортировки пузырьком до численных методов

Модераторы: C_O_D_E, DeeJayC

vga
Сообщения: 9
Зарегистрирован: 16 авг 2004, 15:39
Откуда: Saint-Petersburg
Контактная информация:

20 ноя 2004, 16:17

Доброго времечка, господа!

Есть ли у кого готовый алгоритм склонения по падежам
Фамилии Имени Отчества?

Не требуется абсолютной точности, потому что понятно, что придется подключать 100 Кб словарь исключений. :o
Предполагается, что будет осуществляться визуальный контроль результатов.
---
Best regards,
vga
xpymep
Сообщения: 53
Зарегистрирован: 08 дек 2004, 21:42
Контактная информация:

17 дек 2004, 10:55

Я не вижу тут трудностей...например, такой код:
ПыЗы:
Borland C++ Builder

Код: Выделить всё

#define davatelniy 0x10
char* Padezh(char* slovo,char* okon,int pad)
 {
    AnsiString str = new AnsiString (slovo);
    str.Delete(str.Pos(okon),str.Length);
    switch (pad)
      {
         ....
           case 0x10:
              {
                str+= "у";
                break;
              }
            default:
              throw Exception("Unknown падеж :) ");
         ....
      }

   return str.c_str();
 }
Всего и делов...А вот как программа работает:

Код: Выделить всё

  char sur_name [15] = "Панасенко";
  char name[15] = "Олександр"
  char po_batkovi[15] = "Олександрович";
  char a[15],b[15],c[15];
  strcat (a,padezh(sur_name));
  strcat (b,padezh(name));
  strcat (c,padezh(po_batkovi));
  ShowMessage(AnsiString(a)+"\t"+AnsiString(b)+"\t"+AnsiString(c));
Программа выведет следующее:
Панасенку Олександру Олександровичу
Всего и делов...
DeeJayC
Сообщения: 492
Зарегистрирован: 17 фев 2004, 11:26
Откуда: Ленинград (который Город на Неве)
Контактная информация:

17 дек 2004, 11:07

Особенно хорошо должны при таком раскладе склоняться фамилии, например
Сухих или Ли. Вот здорово-то?
Сухиху и Лиу.
"Особое внимание начинающих аквариумистов хотим обратить на то, что рыбки никогда не спят на спинке!" (c)

viel spass, DeeJayC
vga
Сообщения: 9
Зарегистрирован: 16 авг 2004, 15:39
Откуда: Saint-Petersburg
Контактная информация:

17 дек 2004, 11:21

Спасибо. Трудности как раз не в алгоритме, а найти уже готовые исходики.

Недавно нашел исходики, написанные для 1C и на скороую руку набрасал функции, эмулирующие 1C.
Просьба не ругать, времени не было разбирать исходный код на 1C, который был просто ужасен для чтения;(

Код: Выделить всё

/////////////////////////////////////////////////////////////////////////////
#define C(c, f, s ) ((c) ? (f):(s) )

//------------------------------------------------------------------
class CPadej
{
public:
	CPadej::CPadej() { Clear(); }
	virtual CPadej::~CPadej() { Clear();}
	void Clear();
	CString& Left(const char* sz0, int nCount);
	CString& Trim(const char* sz0);
	CString& Right(const char* sz0, int nCount);
	CString& Mid(const char* sz0, int iFirst);
	CString& Mid(const char* sz0, int iFirst, int nCount);
	CString& TrimRight(const char* sz0);
	CString& ToLow(const char* sz0);
	CString& ToUpper(const char* sz0);
	CString& Replace(const char* sz, const char* sz0, const char* sz1);
	CString& New(const char* sz);
	CString& PadejWord(CString& z1, int z2 = 2, const char* z3="*", int z4=0);
	const char* Padej(CString& z1, int z2=2, int z3=3, CString z4="123", int z5=1);

protected:
	std::vector <CString*> _vStr;

};


//------------------------------------------------------------------
inline int Find(const char* sz0, const char* sz1)
{
	char* p = strstr(sz0, sz1);
	if (!p)
		return 0;
	else
		return p - sz0 + 1;
}

//------------------------------------------------------------------
void CPadej::Clear()
{
	for (size_t i=0; i< _vStr.size(); i++)
	{
		delete _vStr[i];
		_vStr[i] = NULL;
	}
	_vStr.clear();
}

//------------------------------------------------------------------
CString& CPadej::Left(const char* sz0, int nCount)
{
	CString str = sz0;
	if (nCount > str.GetLength())
		nCount = str.GetLength();
	else if (nCount < 0)
		nCount = 0;

	CString* p = new CString();
	*p = str.Left(nCount);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::Trim(const char* sz0)
{
	CString str = sz0;
	CString* p = new CString();
	*p = str.Trim();
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::Right(const char* sz0, int nCount)
{
	CString str = sz0;
	if (nCount > str.GetLength())
		nCount = str.GetLength();
	else if (nCount < 0)
		nCount = 0;

	CString* p = new CString();
	*p = str.Right(nCount);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::Mid(const char* sz0, int iFirst, int nCount)
{
	CString str = sz0;
	if ((iFirst-1) > str.GetLength())
		iFirst = str.GetLength()+1;
	else if ((iFirst-1) < 0)
		iFirst = 1;

	CString* p = new CString();
	*p = str.Mid(iFirst-1, nCount);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::Mid(const char* sz0, int iFirst)
{
	CString str = sz0;
	if ((iFirst-1) > str.GetLength())
		iFirst = str.GetLength()+1;
	else if ((iFirst-1) < 0)
		iFirst = 1;

	CString* p = new CString();
	*p = str.Mid(iFirst-1);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::TrimRight(const char* sz0)
{
	CString str = sz0;
	CString* p = new CString();
	*p = str.TrimRight();
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::ToLow(const char* sz0)
{
	CString* p = new CString();
	*p = sz0;
	_strlwr((char*)(LPCTSTR)*p);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::ToUpper(const char* sz0)
{
	CString* p = new CString();
	*p = sz0;
	_strupr((char*)(LPCTSTR)*p);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::Replace(const char* sz, const char* sz0, const char* sz1)
{
	CString* p = new CString();
	*p = sz;
	p->Replace(sz0, sz1);
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

//------------------------------------------------------------------
CString& CPadej::New(const char* sz)
{
	CString* p = new CString();
	*p = sz;
	_vStr.push_back(p);
	return *_vStr[ _vStr.size()-1 ];
}

// 
// SuperJur.Narod.Ru
// Функция для склонения одного слова!!!
// z1 - само слово
// z2 - номер падежа
// z3 - пол
// z4 - 1-склонять как фамилию, 2-имя, 3-отчество
CString& CPadej::PadejWord(CString& z1, int z2, const char* z3, int z4)
{
	int z5, za, zb, zc, zd, ze;
	const char *z6, *z7, *z8, *z9;
	CString str, str1, str2, str3, str4, str5, str6, str7;
	CString str10, zf;
	z5=Find(z1,"-");
	str10 = "-";
	z6=C(z5==0,"",str10 + PadejWord(Mid(z1,z5+1,strlen(z1)-z5+1),z2,z3,z4));
	z1=ToLow(C(z5==0,z1,Left(z1,z5-1)));
	z7=Right(z1,3);
	z8=Right(z7,2);
	z9=Right(z8,1);
	z5=strlen(z1);
	za=Find("ая ия ел ок яц ий па да ца ша ба та га ка",z8);
	zb=Find("аеёийоуэюяжнгхкчшщ",Left(z7,1));
	zc= z2 < 0 ? -z2:z2;
	zd=C(za==4,5,Find("айяь",z9));
	zd=C((zc==1)||(*z9=='.')||((z4=2)&&(Find(C(*z3=='ч',"оиеу","оиеубвгджзклмнпрстфхцчшщъ"),z9)>0))||
		((z4==1)&&(Find("мия мяэ лия кия жая лея",z7)>0)),9,C((zd==4) && (*z3=='ч'),2,C(z4==1,
		C(Find("оеиую",z9)+Find("их ых аа еа ёа иа оа уа ыа эа юа яа",z8)>0,9,
		C(*z3!='ч',C(za==1,7,C(*z9=='а',C(za>18,1,6),9)),C(((Find("ой ый",z8)>0)&&
		(z5>4)&&( strcmp(Right(z1,4),"опой") != 0 )) || ((zb>10) && (za==16)),8,zd))),zd)));
	ze=Find("лец вей бей дец пец мец нец рец вец аец иец ыец бер",z7);

	zf=C((zd==8)&&(zc!=5),C((zb>15) || ( Find("жий ний",z7)>0),"е","о"),
		C( strcmp(z1,"лев") == 0,"ьв",C((Find("аеёийоуэюя",Mid(z1,z5-3 ,1))==0)&&
		((zb>11) || (zb=0)) && (ze!=45),"",C(za==7,"л",C(za==10,"к",C(za==13,"йц",
		C(ze==0,"",C(ze<12,C(ze==1,"ьц","ь"),C(ze<37,"ц",C(ze<49,"йц","р"))))))))));
	
	str1 = Mid("оыые",Find("внч",z9)+1,1);
	str2 = C(Find("гжкхш",Left(z8,1))>0,"и","ы");
	str3 = "а у а "+ str1 +"ме "+ str2 + " е у ойе я ю я ем" + C(za==16,"и","е")+
		" и е ю ейе и и ь ьюи и и ю ейи ойойу ойойойойуюойойгомуго";
	str4 = Left(z1,z5-C((zd>6) || (*zf!= '\x0'),2,	C(zd>0,1,0)));
	str5 = str3+C((*zf=='е') || (za==16) || ((zb>12) && (zb<16)),"и","ы")+"мм";
	str6 = Mid(str5,10*zd+2*zc-3,2);
	str7 = TrimRight(str6);

	zf=C((zd==9) || ((z4==3) &&  (*z3=='ы')),z1,str4+zf+str7);

	str10 = C(z4>0,ToUpper(Left(zf,1))+C((z2<0)&&(z4>1),".",Mid(zf,2)),zf);
	return New( C( !z1.GetLength(),"",str10+z6));
}

//_____________________________________________________________________________
// z1 - фамилия имя отчество например Железняков Юрий Юрьевич
// z2 - Падеж ( по  умолчанию = 2 - родительный)
// 2 - родительный  ( нет кого?    ) Железнякова Юрия Юрьевича     
// 3 - дательный    ( кому?        ) Железнякову Юрию Юрьевичу 
// 4 - винительный  ( вижу кого?   ) Железнякова Юрия Юрьевича  
// 5 - творительный ( кем?         ) Железняковым Юрием Юрьевичем    
// 6 - предложный   ( о ком?       ) Железнякове Юрии Юрьевиче 
// Если задать Z2 меньше 0, то на выходе получим от -1=Железняков Ю. Ю. до -6=Железнякове Ю. Ю.
// z3 - параметр Пол может не указываться, но при наличии фамилий с 
// инициалами точное определение пола невозможно, поэтому предлагается задавать пол этим
// параметром  1 - мужской 2 - женский  
// ---------------------------------------------------------------------------------------
// Бибик Галушка Цой Николайчик Наталия Петровна Герценберг Кривошей Капица-Метелица
// Если Падеж(Фио ,1 ,3),       то на выходе получим Фамилия Имя Отчество и т.д.
// Если Падеж(Фио ,1 ,3,"1" ),  то                   Фамилия 
// Если Падеж(Фио ,1 ,3,"2" ),  то                   Имя 
// Если Падеж(Фио ,1 ,3,"3" ),  то                   Отчество 
// Если Падеж(Фио, 1 ,3,"12" ), то                   Фамилия Имя 
// Если Падеж(Фио, 1 ,3,"23" ), то                   Имя Отчество 
// Если Падеж(Фио,-1 ,3,"231" ),то                   И. О. Фамилия 
// Если Падеж(Фио,-1 ,3,"23" ), то                   И. О.  
// 10-11-2003 3-20
// z5 - recursion level
const char* CPadej::Padej(CString& z1, int z2, int z3, CString z4, int z5)
{
//	Функция Падеж(z1,z2=2,z3=3,Знач z4="123",z5=1) Экспорт
	Clear();
	CString str, str1, str2, str3, str4, str5;
	CString str10, str11, str15;
	str10 = z4;
	str11 = "ча";
	str15.Format("%d", z5 );

	str1 = Trim(Replace(Mid(z1,Find(z1+" "," ")+1),".",". "));
	str2 = Left(z1,Find(z1+" "," ")-1);
	str3 = Mid( str11+ToLow(Right(z1,1)),z3,1);
	str4 = PadejWord( str2,z2,	str3,z5)+" ";
	str5 = Replace(str10,str15,str4);
	return New( C(z5<4,Padej(str1,z2,z3,	str5,z5+1),z4));
}
Пример использования
Cpadej oPadej;

oPadej.Padej( "Иванов Петр Алексеевич",2, 1));
oPadej.Padej( "Аликперова Нигель Амбросьевна",2, 2));
---
Best regards,
vga
xpymep
Сообщения: 53
Зарегистрирован: 08 дек 2004, 21:42
Контактная информация:

17 дек 2004, 11:46

DeeJayC, тогда надо сделать маленькую мелочь в функцие :

Код: Выделить всё

#define davatelniy 0x10
char* Padezh(char* slovo,char* okon,int pad)
 {
    AnsiString str = new AnsiString (slovo);
if (strcmp(okon,"")==0)
   {
    str.Delete(str.Pos(okon),str.Length);
    switch (pad)
      {
         ....
           case 0x10:
              {
                str+= "у";
                break;
              }
            default:
              throw Exception("Unknown падеж :) ");
         ....
      }
     }

   return str.c_str();
 } 
Естественно, что моя функция не идеальная...
vga, посмотрел на твой алгоритм...тихий ужас :) . Я бы сдох если бы писал это все сам! Но, как говорят, искусство треьует жертв ! :)
vga
Сообщения: 9
Зарегистрирован: 16 авг 2004, 15:39
Откуда: Saint-Petersburg
Контактная информация:

17 дек 2004, 12:10

Это не мой алгоритм, а некого программиста 1C.
Я бы тоже сдох, если бы пытался на с++ перевести нормальным образом ;-)
---
Best regards,
vga
xpymep
Сообщения: 53
Зарегистрирован: 08 дек 2004, 21:42
Контактная информация:

17 дек 2004, 12:23

Я себе представляю такого программиста.... Большая голова, как телевизор,очки 1м на 1м...сидит за стареньким пеньком, а еще лучше за K6 или что-то вроде... Объем винта не более 2Гб,на которых меститься только вин95 и 1С. Наверняка днями не отходит от компа :)
vga
Сообщения: 9
Зарегистрирован: 16 авг 2004, 15:39
Откуда: Saint-Petersburg
Контактная информация:

17 дек 2004, 12:43

Я предполагаю, что такой код очень сильно ускоряет быстродействие 1C скриптов ;-)
---
Best regards,
vga
Аватара пользователя
AiK
Сообщения: 2271
Зарегистрирован: 13 фев 2004, 18:14
Откуда: СПб
Контактная информация:

17 дек 2004, 13:10

Хорош флеймить!
Кстати, фамилия Панасенко по правилам русского языка не склоняется.
Даже самый дурацкий замысел можно воплотить мастерски
xpymep
Сообщения: 53
Зарегистрирован: 08 дек 2004, 21:42
Контактная информация:

17 дек 2004, 18:14

AiK, Гы...точно... Это мой,кста, одноклассник. И моя училка как раз вчера говорила, что в украинском языке его фамилия склоняется, а в русском нет :) . Провтыкал ... надо будет подучиться :)
Ответить