串
串,于我的理解就是字符串
一般认为有三种存储方式:定长顺序串,堆串,块链串(个人认为比较鸡肋)。定长顺序串类似于普通字符串,同数组的大小一样最长长度固定。堆串存储在堆中,空间大小可重新分配。块链串类似于定长顺序串的链表。
定长顺序串与堆串应用较多,定长顺序串的一些操作存在截断问题
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(" 高等规则
");
printf(" α → β1β2…βm
");
printf(" (θδ1δ2…δn) → θδnθδn-1… θδ1θ
");
printf(" 当前规则
");
int i = 0;
while (i < amount) {
printf(" %d、 %s → %s
", 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("文件丢失!
"); 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
", 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条规则,如下所示:
", amount);
int i = 0, j;
while (i < amount) {
printf(" %d、 %s → %s
", i + 1, source[i], object[i]);
i++;
}
printf("输入%d个数表示当前规则的新序号,新序号-1则表示删除该条规则
,保留的规则序号按先后顺序从小到大
请输入:",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("修改已完成
");
}
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表示选择
");
}
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
",s->str); break;
case '0':exit(0); break;
default:
printf("输入有误,请重新选择
");
break;
}
go_on();
}
return 0;
}
2018/10/13