串:串的基本定义及简单应用魔王语言

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kafmws/article/details/83021044

串,于我的理解就是字符串
一般认为有三种存储方式:定长顺序串,堆串,块链串(个人认为比较鸡肋)。定长顺序串类似于普通字符串,同数组的大小一样最长长度固定。堆串存储在堆中,空间大小可重新分配。块链串类似于链表,是极端节省空间的堆串。
定长顺序串与堆串应用较多,定长顺序串的一些操作存在截断问题

ADT String{
  数据对象:串与字符串长度及当前串的最大长度
  结构关系:串中的字符间存在线性关系
  基本运算
  initString(S)  //初始化一个空串
  StringCat(S,T)  //将串T连接至串S末尾
  StringIndexOf(S,T)  //返回串S中第一次出现串T的位置
  StringLastIndexOf(S,T)  //返回串S中最后一次出现串T的位置
  StringInsert(S,pos,T)  //在串S的pos位置插入串T
  StringReplace(S,from,to)  //将串S中的第一个from子串替换为to
  StringReplaceAll(S,from,to)  //将串S中的所有子串from替换为to
  StringReserve(S)  //将串S翻转
  SubString(S,begin,end,T)  //从串S中begin至end取子串T
}ADT String


串的一些基本概念

  • 空串    S ="",串中没有字符,strlen(S) = 0
  • 空格串   "  ",串中的字符全为空格
  • 子串    串的一部分,设串T,串S,StringIndexOf(S,T)结果不为-1,则T为主串S的子串
  • 前缀    对于"abcde",“a”,“ab”,“abc”,“abcd”,“abcde”都是前缀
  • 后缀    对于"abcde",“e”,“de”,“cde”,“bcde”,“abcde”都是后缀
  • 前缀子串  从主串左侧第一个字符开始的所有子串
  • 后缀子串  在主串右侧最后一个字符结束的所有子串
  • 串相等   串长相同,串中每一个位置的字符相同
  • 模式匹配  在主串中寻找子串首次出现位置的运算
  • 真前/后缀(子串)  与主串不相等

堆串的一些基本运算的实现

typedef struct{
	char *str;
	int maxlen;
}String;

void initString(String *s) {
	s->str = (char *)malloc(sizeof(char)*STR);
	s->maxlen = 100;
}

int StringIndexOf(String *s, char sub[]) {//返回子串开始的下标,无则返回-1
	char *str = s->str;
	int i, j;
	for (i = 0; i < strlen(str); i++) {
		j = 0;
		for (j = 0; j < strlen(sub); j++) {
			if (str[i + j] != sub[j])
				break;
		}
		if (j == strlen(sub)) {
			return i;
		}
	}
	return -1;
}

int StringIndexOf(String *s, char c) {
	char *str = s->str;
	for (int i = 0; i < strlen(str); i++) {
		if (str[i] == c)
			return i;
	}
	return -1;
}

int StringLastIndexOf(String *s, char c) {
	char *str = s->str;
	for (int i = strlen(str) - 1; i >=0; i--) {
		if (str[i] == c)
			return i;
	}
	return -1;
}

void StringCat(String *s , char sub[]) {
	char *str = s->str;
	char *re = NULL;
	int len = strlen(str) + strlen(sub);
	if ( len <= s->maxlen) {
		strcat(str,sub);
	}
	else {
		re = (char *)malloc(sizeof(char)*len + 25);
		strcpy(re, str);
		strcat(re, sub);
		free(str);
		s->str = re;
		s->maxlen = len + 24;
	}
}

void StringReplace(String *s, char sub[], char obj[]) {//
	int pos = StringIndexOf(s, sub);
	if (pos == -1)
		return;
	char *str = s->str;
	int subLen = strlen(sub), objLen = strlen(obj);
	char tem[125], *re = NULL;
	strcpy(tem, &str[pos + subLen]);
	int len = strlen(str) - subLen + objLen;
	if (len <= s->maxlen) {
		strcpy(str + pos, obj);
		strcpy(&str[strlen(str)], tem);
	}
	else {
		re = (char *)malloc(sizeof(char)*len + 25);
		strncpy(re, str, pos);
		strcpy(&re[pos],obj);
		strcpy(&re[pos+objLen], tem);
		free(str);
		s->str = re;
		s->maxlen = len + 24;
	}
}

void StringReplace(String *s, int pos, int subLen, char obj[]) {//
	char *str = s->str;
	int objLen = strlen(obj);
	char tem[125], *re = NULL;
	strcpy(tem, &str[pos + subLen]);
	int len = strlen(str) - subLen + objLen;
	if (len <= s->maxlen) {
		strcpy(str + pos, obj);
		strcpy(&str[strlen(str)], tem);
	}
	else {
		re = (char *)malloc(sizeof(char)*len + 25);
		strncpy(re, str, pos);
		strcpy(&re[pos], obj);
		strcpy(&re[pos + objLen], tem);
		free(str);
		s->str = re;
		s->maxlen = len + 24;
	}
}

void StringReplaceAll(String *s, char sub[], char obj[]) {
	int pos;
	int subLen = strlen(sub);
	while ((pos = StringIndexOf(s, sub)) != -1) {
		StringReplace(s, pos, subLen, obj);
	}
}

void StringInsert(String *s , int pos, char in[]) {//从指定位置开始插入字符串
	char *str = s->str;
	char *re = NULL;
	char tem[125];
	strcpy(tem, &str[pos]);
	int requirement = strlen(s->str) + strlen(in);
	if ( requirement <= s->maxlen) {//空间足够
		strcpy(&str[pos], in);
		strcpy(&str[strlen(str)], tem);
	}
	else {
		re = (char *)malloc(sizeof(char)*(requirement + 25));
		strncpy(re, str, pos);
		strcpy(&(re[pos]), in);
		strcpy(&re[strlen(re)], tem);
		free(str);
		s->str = re;
		s->maxlen = requirement + 24;
	}
}

char *SubString(String *s, int begin, int end, char *des) {
	strncpy(des, &(s->str)[begin], end - begin + 1);
	des[end - begin + 1] = 0;
	return des;
}

char *StringReverse(char *str) {
	int i, len = strlen(str);
	char c;
	for (i = 0; i < len / 2; i++) {
		c = str[i];
		str[i] = str[len - i - 1];
		str[len - i - 1] = c;
	}
	return str;
}

魔王语言解释器基于串的实现

两条规则
(1)α->β1β2…βn
(2)(θδ1δ2…δn)->θδnθδn-1…θδ1θ

总觉得跟语法解释器有一点点相似
但是想不到方法去自定义与上述两条规则这种层次的规则

只实现了基于规则(1)的自定义规则,任意字符串可替换为任意字符串
带括号的按规则(2)去解释 可嵌套括号

解释括号的算法

void EliminateBracket(String *s, int left, int right) {//left、right 左右括号的位置
	if (right <= left)
		return;
	char *str = s->str;
	char sub[NUM];
	SubString(s, left+2, right-1, sub);
	char re = str[left + 1];
	StringReverse(sub);
	char resub[NUM*2+1];
	int i, j;
	for (i = 0, j = 0; i < strlen(sub); i++) {
		resub[j++] = re;
		resub[j++] = sub[i];
	}
	resub[j++] = re;
	resub[j] = 0;
	StringReplace(s, left, right-left+1, resub);//int pos, int subLen  这个方法的第三个参数为被替换串的串长
	left = StringLastIndexOf(s, '('), right = StringIndexOf(s, ')');
	EliminateBracket(s, left, right);//递归消除括号
}

总体实现

//全局变量
int amount = 0;//规则条数
char source[NUM][LEN], object[NUM][LEN];//字符串数组,相同下标的两个source串和object串分别表示一条规则中的被替换串与用来替换的串

void check_rule() {//打印规则
	system("cls");
	printf("\t\t高等规则\n");
	printf("\tα   →   β1β2…βm\n");
	printf("\t(θδ1δ2…δn)   →   θδnθδn-1… θδ1θ\n\n");
	printf("\t\t当前规则\n");
	int i = 0;
	while (i < amount) {
		printf("\t%d、\t%s   →   %s\n", i + 1, source[i], object[i]);
		i++;
	}
}

int import_rule() {//从文件中读入规则
	int i = 0, j = 0;
	FILE *fp = fopen("TheLanguageOftheKingOftheDevil.rule", "r");
	if (fp == NULL) { printf("文件丢失!\n"); return 0; }
	while (fscanf(fp,"%s   →   %s", source[i++], object[j++]) != EOF);
	if (i != j) {
		printf("文件损坏!");
	}
	fclose(fp);
	return i-1;
}

void write_rule() {//将规则写入文件
	int i;
	FILE *fp = fopen("TheLanguageOftheKingOftheDevil.rule", "w");
	for (i = 0; i < amount; i++) {
		fprintf(fp, "%s   →   %s\n", source[i], object[i]);
	}
	fclose(fp);
}

void use_rule(String *s) {//使用规则
	int i;
	for (i = 0; i < amount;i++) {
		StringReplaceAll(s, source[i], object[i]);
	}
	EliminateBracket(s, StringLastIndexOf(s, '('), StringIndexOf(s, ')'));
}

void add_rule() {
	char from[NUM], to[NUM];
	printf("请输入要转换的魔王词汇:");
	scanf("%s", from);
	printf("请输入该词汇对应的内容:");
	scanf("%s", to);
	if (confirm()) {
		strcpy(source[amount], from);
		strcpy(object[amount++], to);
		//保存到文件
		write_rule();
	}
	else {//取消
		printf("本次修改已取消");
	}
}

void sort_rule() {
	printf("现在一共有%d条规则,如下所示:\n", amount);
	int i = 0, j;
	while (i < amount) {
		printf("\t%d、\t%s   →   %s\n", i + 1, source[i], object[i]);
		i++;
	}
	printf("输入%d个数表示当前规则的新序号,新序号-1则表示删除该条规则\n,保留的规则序号按先后顺序从小到大\n请输入:",amount);
	int order[NUM], cnt = 0;
	char Tsource[NUM][LEN], Tobject[NUM][LEN];
	for (i = 0; i < amount; i++) {
		scanf("%d", &order[i]);
		if (order[i] != -1)
			cnt++;
		strcpy(Tsource[i], source[i]);
		strcpy(Tobject[i], object[i]);
	}
	for (i = 1; i < cnt; i++) {//根据order排序
		for (j = 0; j < amount; j++) {
			if (order[j] == i)
			break;
		}
		strcpy(source[i - 1], Tsource[j]);
		strcpy(object[i - 1], Tobject[j]);
	}
	amount = cnt;
	write_rule();
	printf("修改已完成\n");
}

void go_on() {
	printf("按任意键继续");
	getch();
	//getch();VS下可能需要两个getch()
}

int confirm() {
	char choice[25] , flag = 1;
	printf("是否确认本次操作?(0/1):");
	do {
		if (flag == 0) {
			printf("请输入0或1表示选择\n");
		}
		scanf("%s", choice);
	} while (choice[0] != '0' && choice[0] != '1');
	return choice[0] - '0';
}

int main() {
	//return 0;
	char choice[20];
	amount = import_rule();
	String ss;
	String *s = &ss;
	initString(s);
	while (1) {
		menu();
		scanf("%s", choice);
		switch (choice[0]){
		case '1':check_rule(); break;
		case '2':add_rule(); break;
		case '3':sort_rule(); break;
		case '4':printf("请输入待解释字符串:"); scanf("%s", s->str); use_rule(s); printf("结果为:%s\n",s->str); break;
		case '0':exit(0); break;
		default:
			printf("输入有误,请重新选择\n");
			break;
		}
		go_on();
	}
	return 0;
}

2018/10/13

猜你喜欢

转载自blog.csdn.net/kafmws/article/details/83021044
今日推荐