String.cRUN

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h> //atoi等函数
#include <string.h>

//不借助系统函数,实现字符串的相关功能
// 字符串和数组最大的差别:字符串自带结束标记'\0',不需要额外的字符串长度;数组需要知道数组长度。
//printf("%c", ch) 和 putchar(ch)等价
//printf("%s", str) 和 puts(str)等价



//遍历,通过'\0'停止循环
void TravelString(const char *str)
{
	const char* p = str;
	while (*p != '\0')
	{
		char ch = *p;
		putchar(ch);
		p++;
	}
	putchar('\n');
}

void TravelString2(const char* str)
{
	//'\0'的ASCII码就是0。换一个写法
	for(const char* p = str; *p != 0; p++)
	{
		putchar(*p);
	}
	putchar('\n');
}


//字符串长度,不包含结尾的'\0'
int StringLen(const char* str)
{
	int len = 0;
	for (; *str != '\0'; str++) len++;

	return len;
}


//反转字符串,
void FlipString_0(char* str)
{
	int len = StringLen(str); 

	//对称交换字符; 
	//len是奇数,如9,len/2是4, [0,4)一共4对字符要交换。独立第4个字符不需要交换;
	//len是偶数,如8,len/2是4,[0,4)一共4对字符要交换。
	for (int i = 0; i < len/2; i++)
	{
		char temp = str[i];
		str[i] = str[len-1 - i];
		str[len - 1 - i] = temp;
	}
}

void FlipString_arry(char* str)
{
	int len = StringLen(str);

	//对称交换字符; 不需要考虑奇数偶数,两端出发,向中间靠齐
	int left = 0, right = len - 1;
	while(left < right)
	{
		char temp = str[left];
		str[left] = str[right];
		str[right] = temp;

		left++, right--;
	}
}

void FlipString_pointer(char* str)
{
	int len = StringLen(str);

	//对称交换字符; 不需要考虑奇数偶数,两端出发,向中间靠齐
	char *left = str;
	char *right = str + (len - 1);
	while (left < right)
	{
		char temp = *left;
		*left = *right;
		*right = temp;

		left++, right--;
	}
}


//反转字符串。假定dst已经分配好内存
void FlipString2(const char* src, char* dst)
{
	int len = StringLen(src); //len为内存中长度-1
	for (int i = 0; i <= len; i++)
	{
		dst[i] = src[len - 1 - i];
	}
	//字符串结尾
	dst[len] = '\0';
}

//字符串与数字的相互转换
void Test_NumberString()
{
	//字符串转整数,
	int num;
	{
		char str[] = "100";
		num = atoi(str);
	}

	//字符串转小数或者整数
	{
		char str[] = "100 11.11";
		int inum;
		double dnum;
		sscanf(str, "%d %lf", &inum, &dnum);
	}
	{
		double dnum = atof("1.235");
	}
	

	//小数整数转字符串
	{
		char str[256];
		double num = 12.34;
		sprintf(str, "%lf", num);

	}

	return;
}

//单词分割。使用<string.h>提供函数strtok
//https://www.cplusplus.com/reference/cstring/strtok/
void WordSplit_strtok(char* str)
{
	char deli[] = " .,?\n";//用字符' ''.'来分割,之一
	char* p = strtok(str, deli);
	while (p)
	{
		printf("%s\n", p);
		p = strtok(NULL, deli); //继续查找
	}
}


//c是否包含在strTemplate中
int IsOneOf(char c, const char* strTemplate)
{
	for (const char* p = strTemplate; *p != '\0'; p++)
		if (*p == c) return 1;
	return 0;
}

int IsOneOf_(char c, const char* strTemplate)
{
	for (const char* p = strTemplate; *p != '\0'; p++)
		if (*p == c) return 1;
	return 0;
}

//掠过包含在delimiter中的字符,直到出现新字符或者结尾空字符
const char* SkipDelimiter(const char* str, const char* delimiter)
{
	const char* p = str;
	while(*p && IsOneOf(*p, delimiter)) p++;
	return p;
}

//提取单词,直到出现模板delimiter中的字符,单词存在word中
const char* ExtractWord(const char* str, const char* delimiter, char *word)
{
	const char* src = str;
	char* dst = word;
	while (*src && !IsOneOf(*src, delimiter))
	{
		*dst = *src;
		src++, dst++;
	}
	*dst = '\0'; //加上字符串结尾标记,封住word
	return src;
}

//单词分割
void WordSplit(const char *str)
{
	char delimiter[] = " .,?";  //用字符' ''.''?'来分割单词
	const char* p = SkipDelimiter(str, delimiter);
	while (*p)
	{
		char msg[128];
		p = ExtractWord(p, delimiter, msg); //提取正常字符
		puts(msg);
		p = SkipDelimiter(p, delimiter); //掠过间隔字符
	}
}

//单词分割(用字符' ''.''?'来分割单词),单个函数版本
//比较WordSplit_和WordSplit的难度
//如果需要扩充间隔符,代码的可读性和一致性会变得很差【多处出现比较的代码】
void WordSplit_(const char* str)
{
	const char* p = str;
	while (*p && (*p == ' ' || *p == '.' || *p == ',' || *p == '?')) p++; //掠过间隔字符
	while (*p)
	{
		char word[128];
		{//提取单词
			char* dst = word;
			while (*p && !(*p == ' ' || *p == '.' || *p == ',' || *p == '?'))
			{
				*dst = *p;
				p++, dst++;
			}
			*dst = '\0'; //加上字符串结尾标记,封住字符串word
		}
		puts(word);
		while (*p && (*p == ' ' || *p == '.' || *p == ',' || *p == '?')) p++; //掠过间隔字符
	}
}

void Test_WordSplit()
{
	char str[] = " I am  just a   word, and you?";
	//WordSplit(str);
	WordSplit_(str);
	//WordSplit_strtok(str);
}

void Test_Travel()
{
	char str[] = "I am a string.";
	TravelString2(str);
	printf("%s\n", str);
}


void Test_FilpString()
{
	char str0[] = "012345678";
	FlipString_pointer(str0);
	printf("%s\n", str0);

	char str2[256];
	FlipString2(str0, str2);
	printf("%s\n", str2);
}


int main()
{
	Test_WordSplit();
	//Test_FilpString();


	return 0;
}