C, C++ 문법

텍스트 간결하게 편집 중복공백 중복개행 주석 제거

디버그정 2022. 8. 27. 12:28
// 텍스트에서 중복 공백이나 중복 개행 제거, 주석을 포함시키지 않고 순수 내용만 간결하게 남긴다.
// 길이가 줄어드므로 소스와 버프에 동일 주소를 지정해도 된다.
TCHAR * __stdcall ConsciseText(TCHAR *buf, const TCHAR *src)
{
	TCHAR *p, *q;

	p = (TCHAR *)src;	// 소스 포인터
	q = buf;			// 버프 포인터
	
	for (; ; )
	{
		if (!*p)	// 문자열 맨 끝 널문자인 경우
		{
			if (q != buf)	// ★ 논리상 버퍼 기록 여부를 먼저 판단해야 q[-1] 조건이 유효하다. 더 아래에서도 마찬가지로 조건문에서 가장 앞에 두어야 한다.
			{
				if (q[-1] == ' ')	// 문자열-공백-널문자순인 경우 공백은 무의미하므로 1칸 앞으로 당긴다.
					--q;
				/* 마지막 개행을 제거하고자 할 때 주석 해제. 보통 편의상 마지막 개행은 남겨둔다.
				if (q[-1] == '\n')
					--q;
				if (q[-1] == '\r')	// 윈도우 시스템의 개행은 \r\n 2문자
					--q;
				*/
			}
			break;
		}

		if (*p == ' ' || *p == VK_TAB)	// 공백인 경우
		{
			if (q == buf || q[-1] == ' ' || q[-1] == VK_TAB || q[-1] == '\n')	// 버퍼 미기록 상태(처음부터 공백) 또는 이전이 공백, 개행이면 기록하지 않는다.
			{
				++p;
				continue;	// 더 아래로 진행하지 않고 건너뛴다.
			}
			
			// 탭을 스페이스로 바꾸는 경우. 탭을 그대로 유지하려면 아래 3줄을 주석처리한다.			
			*q++ = ' ';	// 공백을 스페이스 하나로 일치
			++p;
			continue;
		}
		else if (*p == '\r' || *p == '\n')	// 개행인 경우
		{
			if (q == buf || q[-1] == '\n')	// 버퍼 미기록 상태(처음부터 개행) 또는 이전이 개행이면 기록하지 않는다.
			{
				if (*p == '\r')		// 참고로 윈도우의 개행은 \r\n이고 유닉스 등은 \n이다.
					p += 2;
				else
					++p;
				continue;
			}
			
			if (q != buf && q[-1] == ' ')	// 문자열-공백-개행순인 경우 공백은 무의미하므로 1칸 앞으로 당긴다.
				--q;
		}
		else if (*p == '/')	// 주석 표시 고려
		{
			if (p[1] == '/')	// 주석이 //인 경우 개행 전까지 무시
			{
				for (p += 2; *p && !(*p == '\r' || *p == '\n'); ++p);
				continue;
			}
			else if (p[1] == '*')	// 주석이 /*인 경우 */까지 무시
			{
				for (p += 2; *p; ++p)
				{
					if (*p == '*' && p[1] == '/')
					{
						p += 2;
						break;
					}
				}
				continue;
			}
		}

		*q++ = *p++;
	}
	*q = '\0';

	return buf;
}