ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > Программирование > С/С++, C#, Delphi, .NET, Asm
   
Закрытая тема
 
Опции темы Поиск в этой теме Опции просмотра

[C++] Class: Tokenize
  #1  
Старый 17.02.2008, 03:25
razzzar
Участник форума
Регистрация: 16.06.2007
Сообщений: 107
Провел на форуме:
725870

Репутация: 208
Arrow [C++] Class: Tokenize

Наверное все сталкивались с проблемой когда надо разбить строку по разделителям в многопоточном приложении. Функция strtok(); для этого не подходит, так как она использует статические элементы и при одновременом вызове в двух или более потоках работать будет некоректно ( я говорю о потоках, вызваных с помощью WinApi фун-ции CreateThread();, при использовании _beginthread она будет работать корректно, см. Рихтера ). Недавно я столкнулся с такой проблеме в одном из своих проектов, и для таких целей написал класс токенайзера.

Объявление:
Код:
class Tokenize
{
public:
	Tokenize();
	~Tokenize();
	void SetOriginalString(char * szString);
	char * GetOriginalString();
	void SetTokens(char * szToken);
	char * GetNextToken();
	char * GetCurrentToken();
private:
	std::string strOriginalString;
	std::string strToken;
	std::string strString;
	bool bFinished;
	int nCurrentPointer;
};
Описание:
Код:
Tokenize::Tokenize()
{
	strString.assign("");
	bFinished = false;
}

Tokenize::~Tokenize()
{
}

void Tokenize::SetOriginalString(char * szString)
{
	strOriginalString.assign(szString);
	strString.assign("");
	strToken.assign("");
	bFinished = false;
	nCurrentPointer = -1;
}

char * Tokenize::GetOriginalString()
{
	return (char *) strOriginalString.c_str();
}

void Tokenize::SetTokens(char * szToken)
{
	strToken.assign(szToken);
}

char * Tokenize::GetNextToken()
{
	if ( bFinished == true )
	{
		return NULL;
	}
	
	if ( nCurrentPointer == -1 )
	{
		nCurrentPointer = (int) strOriginalString.find_first_of(strToken, 0);
		if ( nCurrentPointer == -1 )
		{
			nCurrentPointer = (int) strOriginalString.find("\0", 0);
			bFinished = true;
			if ( nCurrentPointer == -1 )
			{
				return NULL;
			}
			return (char *) strOriginalString.c_str();
		}
		strString.assign(strOriginalString.substr(0, nCurrentPointer));
		return (char *) strString.c_str();
	}
	else
	{
		int nPrevPointer = nCurrentPointer + 1;
		nCurrentPointer = (int) strOriginalString.find_first_of(strToken, nPrevPointer);
		if ( nCurrentPointer == -1 )
		{
			nCurrentPointer = (int) strOriginalString.find("\0", nPrevPointer);
			bFinished = true;
			if ( nCurrentPointer == -1 )
			{
				return NULL;
			}
			strString.assign(strOriginalString.substr(nPrevPointer, nCurrentPointer));
			return (char *) strString.c_str();
		}
		strString.assign(strOriginalString.substr(nPrevPointer, nCurrentPointer - nPrevPointer));
		return (char *) strString.c_str();
	}
}

char * Tokenize::GetCurrentToken()
{
	return (char *) strString.c_str();
}
Пример использования:
Код:
Tokenize tok;

tok.SetOriginalString("qwe|asd,zxc.ghj");
tok.SetTokens("|,.");

while ( tok.GetNextToken() != NULL )
{
	MessageBox(0, tok.GetCurrentToken(), "Tokenize", 0);
}
 

  #2  
Старый 17.02.2008, 04:05
KEZ
Banned
Регистрация: 18.05.2005
Сообщений: 1,981
Провел на форуме:
1941233

Репутация: 2726


По умолчанию

Круто.

Цитата:
return (char *) strString.c_str();
const тебе для прикола дали видимо.

Затем идут два практически идентичных куска, которые ты расписал по отдельности.

Причем интересно, внутри класса ты юзаешь std::string, а выводишь в "не-const" char*.
Такая обертка в обратную сторону. Сделано это видимо было для снижения скорости, ибо коду опять получилось столько же, сколько нужно для того, чтоб char* обработать руками ...

Цитата:
return NULL;
кросс-платформенность?

Но все же это правильнее (намного), чем сорцы Кузьмича. И вообще для античата даже... можно сказать, слишком круто. Так что плюсадин.

PS

Цитата:
Tokenize::~Tokenize()
{
}
=\\\\

Последний раз редактировалось KEZ; 17.02.2008 в 04:12..
 

  #3  
Старый 17.02.2008, 05:23
KEZ
Banned
Регистрация: 18.05.2005
Сообщений: 1,981
Провел на форуме:
1941233

Репутация: 2726


По умолчанию

Код:
// ...

class Tokenize
{

public:

	void Reset()
	{
		m_Pos = m_Source;
	}

	Tokenize(const char * Src,const char * Tokens = "|")
	{
		m_Pos = m_Source = strdup(Src);
		m_End = m_Pos+strlen(m_Pos);
		mg_Ret = 0;
		m_Tokens = strdup(Tokens);
	}

	~Tokenize()
	{
		delete m_Source;
		if (m_Tokens)
			delete m_Tokens;
		if (mg_Ret)
			delete mg_Ret;
	}

	const char * GetNextToken()
	{
		if (mg_Ret)
		{
			delete mg_Ret;
			mg_Ret = 0;
		}

		if (!*m_Pos)
			return 0;

		if (m_Tokens)
		{
			const char * nextpos = token_first();
			unsigned curlen = (unsigned)(nextpos - m_Pos + 1);
			mg_Ret = (char*)malloc(curlen);
			lstrcpyn(mg_Ret,m_Pos,curlen);
			m_Pos = nextpos;
			if (m_Pos[0]) ++m_Pos;
		}

		return mg_Ret;
	}

private:
	const char * m_Pos, * m_Tokens, * m_Source, * m_End;
	char * mg_Ret;

	const char * token_first()
	{
		unsigned i = 0;
		char c;
		const char * m = m_End;
		while (c=m_Tokens[i++])
		{
			char * d = strchr(m_Pos,c);
			if (d && d < m)
				m = d;
		}
		return m;
	}
};

// ...

int main()
{
	Tokenize tok("abc|def|ghi.sex.dax/big/min",".|/");
	const char * part;
	while (part = tok.GetNextToken())
	{
		MessageBox(0, part, "Tokenize 1", MB_ICONEXCLAMATION);
	}
	tok.Reset();
	while (part = tok.GetNextToken())
	{
		MessageBox(0, part, "Tokenize 2", MB_ICONINFORMATION);
	}

	return 0;
}

// ...
 

  #4  
Старый 17.02.2008, 19:23
razzzar
Участник форума
Регистрация: 16.06.2007
Сообщений: 107
Провел на форуме:
725870

Репутация: 208
По умолчанию

KEZ, класс писался под мой проект, и там мне надо чтобы возвращало именно char *, поэтому я его и возвращаю. Кому надо спокойно может переделать чтобы возвращало то что ему нужно
Что тебе не нравится в пустом деструкторе?
Чем напрягает return NULL; это одно и тоже что написать return 0; Все-равно при компиляции компилятор так и сделает, т.к. NULL определен посредством #define в 0 =\

Теперь насчет твоего кода
Код:
Tokenize(const char * Src,const char * Tokens = "|")
	{
		m_Pos = m_Source = strdup(Src);
		m_End = m_Pos+strlen(m_Pos);
		mg_Ret = 0;
		m_Tokens = strdup(Tokens);
	}

	~Tokenize()
	{
		delete m_Source;
		if (m_Tokens)
			delete m_Tokens;
		if (mg_Ret)
			delete mg_Ret;
	}
Сначала определяешь строку как m_Source = strdup(Src); средствами crt, а потом ее удаляешь уже средствами C++: delete m_Source; причем правильно было бы указать так: delete [] m_Source;
 

  #5  
Старый 18.02.2008, 00:18
KEZ
Banned
Регистрация: 18.05.2005
Сообщений: 1,981
Провел на форуме:
1941233

Репутация: 2726


По умолчанию

Цитата:
KEZ, класс писался под мой проект, и там мне надо чтобы возвращало именно char *, поэтому я его и возвращаю.
Значит твой проэкт неправильно составлен, т.к. если надо char* - значит ты будешь модифицировать в дальнейшем, что непрвильно.

Цитата:
Что тебе не нравится в пустом деструкторе?
То, что он не несет в себе ничего нужного, зачем его писать?

Цитата:
Сначала определяешь строку как m_Source = strdup(Src); средствами crt, а потом ее удаляешь уже средствами C++: delete m_Source;
Да, надо было написать там соотв. free. Торопился. И lstrcpyn() виндовая - это тоже.
 

  #6  
Старый 18.02.2008, 00:33
Forcer
Постоянный
Регистрация: 12.04.2007
Сообщений: 413
Провел на форуме:
3578578

Репутация: 275
Отправить сообщение для Forcer с помощью ICQ
По умолчанию

Цитата:
Чем напрягает return NULL; это одно и тоже что написать return 0; Все-равно при компиляции компилятор так и сделает, т.к. NULL определен посредством #define в 0 =\
В С++ нет константы NULL. Без подключения заголовочного файла работать не будет, поэтому рекомендуется использовать обычный 0.
 

  #7  
Старый 18.02.2008, 01:02
razzzar
Участник форума
Регистрация: 16.06.2007
Сообщений: 107
Провел на форуме:
725870

Репутация: 208
По умолчанию

Forcer,
эта константа есть в заголовочном файле который я подключаю. поэтому напрягом по ее исопльзованию не вижу. все0равно везде заменится на 0. просто я привык при работе с указателями присваивать им NULL, а обычным переменным 0
KEZ,
на счет деструктура ступил, мой косяк почему-то показалось что если нельзя объявлять класс без конструктора, то нельзя и без деструктора ) забылся )
а char * у меня там возвращается потому что используется в функциях которые требуют этот тип
 

  #8  
Старый 18.02.2008, 01:41
noobyara
Новичок
Регистрация: 27.01.2008
Сообщений: 13
Провел на форуме:
210819

Репутация: 26
По умолчанию

Цитата:
Сообщение от razzzar  
нельзя объявлять класс без конструктора
я что-то пропустил? откуда этот запрет?
Цитата:
Сообщение от razzzar  
а char * у меня там возвращается потому что используется в функциях которые требуют этот тип
это не тип а указатель на тип, про const совет дельный..
 

  #9  
Старый 18.02.2008, 01:51
razzzar
Участник форума
Регистрация: 16.06.2007
Сообщений: 107
Провел на форуме:
725870

Репутация: 208
По умолчанию

noobyara,
читай внимательно =\
Цитата:
почему-то показалось что если нельзя объявлять класс без конструктора, то нельзя и без деструктора ) забылся )
про const я уже как-то сам разберусь, оно не шибко и важно. а про указатели на тип поправляй 5класников всем и так ясно что имелось в виду
 

  #10  
Старый 18.02.2008, 04:06
noobyara
Новичок
Регистрация: 27.01.2008
Сообщений: 13
Провел на форуме:
210819

Репутация: 26
По умолчанию

Цитата:
Сообщение от razzzar  
noobyara,
читай внимательно =\
месяц не курю.. перечитал, еще перечитал...
почему-то показалось, что первая часть предложения несет в себе утверждение("если нельзя объявлять класс без конструктора"), возможно я не дорос до вашего возраста и мне это только кажется..
или вы имели ввиду, что при использовании конструктора обязательно должен использоваться деструктор(что тоже неправильно), тогда вы знаете, что излагать свои мысли правильно учат еще до того момента, как вы пойдете в пятый класс..

Цитата:
Сообщение от razzzar  
noobyara,
а про указатели на тип поправляй 5класников
я про тип упомянул, лишь по тому поводу, что KEZ в своем коде тоже тип char использует, и разница в указателях. это на самом деле не важно, как я теперь понял, и судя по всему, в большей степени зависит не от ситуации, а от человека, пишущего код..

ухожу из темы наоффтопил и так немало, за классы спасибо.

*noobyara ушел учить пятиклашек "азбуке С++"..

Последний раз редактировалось noobyara; 18.02.2008 в 04:20..
 
Закрытая тема



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
mrim class Sharky PHP, PERL, MySQL, JavaScript 4 11.12.2007 23:00



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ